@finos/legend-query-builder 4.14.68 → 4.14.70
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/lib/__lib__/QueryBuilderTesting.d.ts +1 -0
- package/lib/__lib__/QueryBuilderTesting.d.ts.map +1 -1
- package/lib/__lib__/QueryBuilderTesting.js +1 -0
- package/lib/__lib__/QueryBuilderTesting.js.map +1 -1
- package/lib/components/explorer/QueryBuilderExplorerPanel.d.ts +1 -0
- package/lib/components/explorer/QueryBuilderExplorerPanel.d.ts.map +1 -1
- package/lib/components/explorer/QueryBuilderExplorerPanel.js +95 -53
- package/lib/components/explorer/QueryBuilderExplorerPanel.js.map +1 -1
- package/lib/components/explorer/QueryBuilderPropertySearchPanel.d.ts +4 -0
- package/lib/components/explorer/QueryBuilderPropertySearchPanel.d.ts.map +1 -1
- package/lib/components/explorer/QueryBuilderPropertySearchPanel.js +172 -108
- package/lib/components/explorer/QueryBuilderPropertySearchPanel.js.map +1 -1
- package/lib/components/fetch-structure/QueryBuilderPostFilterPanel.d.ts.map +1 -1
- package/lib/components/fetch-structure/QueryBuilderPostFilterPanel.js +2 -1
- package/lib/components/fetch-structure/QueryBuilderPostFilterPanel.js.map +1 -1
- package/lib/components/fetch-structure/QueryBuilderTDSPanel.d.ts.map +1 -1
- package/lib/components/fetch-structure/QueryBuilderTDSPanel.js +29 -18
- package/lib/components/fetch-structure/QueryBuilderTDSPanel.js.map +1 -1
- package/lib/components/fetch-structure/QueryBuilderTDSWindowPanel.d.ts.map +1 -1
- package/lib/components/fetch-structure/QueryBuilderTDSWindowPanel.js +13 -4
- package/lib/components/fetch-structure/QueryBuilderTDSWindowPanel.js.map +1 -1
- package/lib/components/filter/QueryBuilderFilterPanel.d.ts.map +1 -1
- package/lib/components/filter/QueryBuilderFilterPanel.js +4 -3
- package/lib/components/filter/QueryBuilderFilterPanel.js.map +1 -1
- package/lib/components/result/QueryBuilderResultPanel.d.ts +12 -0
- package/lib/components/result/QueryBuilderResultPanel.d.ts.map +1 -1
- package/lib/components/result/QueryBuilderResultPanel.js +60 -8
- package/lib/components/result/QueryBuilderResultPanel.js.map +1 -1
- package/lib/components/result/tds/QueryBuilderTDSGridResult.d.ts.map +1 -1
- package/lib/components/result/tds/QueryBuilderTDSGridResult.js +47 -28
- package/lib/components/result/tds/QueryBuilderTDSGridResult.js.map +1 -1
- package/lib/components/result/tds/QueryBuilderTDSSimpleGridResult.d.ts +1 -0
- package/lib/components/result/tds/QueryBuilderTDSSimpleGridResult.d.ts.map +1 -1
- package/lib/components/result/tds/QueryBuilderTDSSimpleGridResult.js +34 -1
- package/lib/components/result/tds/QueryBuilderTDSSimpleGridResult.js.map +1 -1
- package/lib/components/shared/QueryBuilderFilterHelper.d.ts.map +1 -1
- package/lib/components/shared/QueryBuilderFilterHelper.js +3 -0
- package/lib/components/shared/QueryBuilderFilterHelper.js.map +1 -1
- package/lib/components/shared/QueryBuilderPropertyInfoTooltip.d.ts +11 -0
- package/lib/components/shared/QueryBuilderPropertyInfoTooltip.d.ts.map +1 -1
- package/lib/components/shared/QueryBuilderPropertyInfoTooltip.js +6 -3
- package/lib/components/shared/QueryBuilderPropertyInfoTooltip.js.map +1 -1
- package/lib/graph-manager/QueryBuilderConfig.d.ts +4 -0
- package/lib/graph-manager/QueryBuilderConfig.d.ts.map +1 -1
- package/lib/graph-manager/QueryBuilderConfig.js +5 -0
- package/lib/graph-manager/QueryBuilderConfig.js.map +1 -1
- package/lib/index.css +2 -2
- package/lib/index.css.map +1 -1
- package/lib/package.json +1 -1
- package/lib/stores/QueryBuilderResultState.d.ts +11 -3
- package/lib/stores/QueryBuilderResultState.d.ts.map +1 -1
- package/lib/stores/QueryBuilderResultState.js +47 -4
- package/lib/stores/QueryBuilderResultState.js.map +1 -1
- package/lib/stores/QueryBuilderValueSpecificationBuilderHelper.d.ts +4 -0
- package/lib/stores/QueryBuilderValueSpecificationBuilderHelper.d.ts.map +1 -1
- package/lib/stores/explorer/QueryBuilderExplorerState.d.ts +5 -1
- package/lib/stores/explorer/QueryBuilderExplorerState.d.ts.map +1 -1
- package/lib/stores/explorer/QueryBuilderExplorerState.js +80 -10
- package/lib/stores/explorer/QueryBuilderExplorerState.js.map +1 -1
- package/lib/stores/explorer/QueryBuilderFuzzySearchAdvancedConfigState.d.ts +24 -0
- package/lib/stores/explorer/QueryBuilderFuzzySearchAdvancedConfigState.d.ts.map +1 -0
- package/lib/stores/explorer/QueryBuilderFuzzySearchAdvancedConfigState.js +39 -0
- package/lib/stores/explorer/QueryBuilderFuzzySearchAdvancedConfigState.js.map +1 -0
- package/lib/stores/explorer/QueryBuilderPropertySearchState.d.ts +8 -4
- package/lib/stores/explorer/QueryBuilderPropertySearchState.d.ts.map +1 -1
- package/lib/stores/explorer/QueryBuilderPropertySearchState.js +204 -114
- package/lib/stores/explorer/QueryBuilderPropertySearchState.js.map +1 -1
- package/lib/stores/fetch-structure/tds/post-filter/QueryBuilderPostFilterState.d.ts.map +1 -1
- package/lib/stores/fetch-structure/tds/post-filter/QueryBuilderPostFilterState.js +8 -1
- package/lib/stores/fetch-structure/tds/post-filter/QueryBuilderPostFilterState.js.map +1 -1
- package/lib/stores/fetch-structure/tds/projection/QueryBuilderProjectionValueSpecificationBuilder.d.ts.map +1 -1
- package/lib/stores/fetch-structure/tds/projection/QueryBuilderProjectionValueSpecificationBuilder.js +12 -1
- package/lib/stores/fetch-structure/tds/projection/QueryBuilderProjectionValueSpecificationBuilder.js.map +1 -1
- package/lib/stores/filter/QueryBuilderFilterState.d.ts +8 -1
- package/lib/stores/filter/QueryBuilderFilterState.d.ts.map +1 -1
- package/lib/stores/filter/QueryBuilderFilterState.js +27 -10
- package/lib/stores/filter/QueryBuilderFilterState.js.map +1 -1
- package/lib/stores/shared/ValueSpecificationEditorHelper.d.ts +1 -0
- package/lib/stores/shared/ValueSpecificationEditorHelper.d.ts.map +1 -1
- package/lib/stores/shared/ValueSpecificationEditorHelper.js +6 -2
- package/lib/stores/shared/ValueSpecificationEditorHelper.js.map +1 -1
- package/package.json +9 -9
- package/src/__lib__/QueryBuilderTesting.ts +1 -0
- package/src/components/explorer/QueryBuilderExplorerPanel.tsx +228 -115
- package/src/components/explorer/QueryBuilderPropertySearchPanel.tsx +618 -388
- package/src/components/fetch-structure/QueryBuilderPostFilterPanel.tsx +5 -2
- package/src/components/fetch-structure/QueryBuilderTDSPanel.tsx +78 -44
- package/src/components/fetch-structure/QueryBuilderTDSWindowPanel.tsx +63 -10
- package/src/components/filter/QueryBuilderFilterPanel.tsx +4 -2
- package/src/components/result/QueryBuilderResultPanel.tsx +207 -20
- package/src/components/result/tds/QueryBuilderTDSGridResult.tsx +57 -38
- package/src/components/result/tds/QueryBuilderTDSSimpleGridResult.tsx +43 -0
- package/src/components/shared/QueryBuilderFilterHelper.ts +8 -0
- package/src/components/shared/QueryBuilderPropertyInfoTooltip.tsx +13 -3
- package/src/graph-manager/QueryBuilderConfig.ts +6 -0
- package/src/stores/QueryBuilderResultState.ts +64 -10
- package/src/stores/QueryBuilderValueSpecificationBuilderHelper.ts +5 -0
- package/src/stores/explorer/QueryBuilderExplorerState.ts +112 -8
- package/src/stores/explorer/QueryBuilderFuzzySearchAdvancedConfigState.ts +46 -0
- package/src/stores/explorer/QueryBuilderPropertySearchState.ts +280 -142
- package/src/stores/fetch-structure/tds/post-filter/QueryBuilderPostFilterState.ts +8 -1
- package/src/stores/fetch-structure/tds/projection/QueryBuilderProjectionValueSpecificationBuilder.ts +15 -2
- package/src/stores/filter/QueryBuilderFilterState.ts +34 -11
- package/src/stores/shared/ValueSpecificationEditorHelper.ts +9 -1
- package/tsconfig.json +1 -0
|
@@ -61,6 +61,7 @@ import {
|
|
|
61
61
|
Dialog,
|
|
62
62
|
CustomSelectorInput,
|
|
63
63
|
} from '@finos/legend-art';
|
|
64
|
+
import { getFloatGridColumnCustomHeader } from './QueryBuilderTDSSimpleGridResult.js';
|
|
64
65
|
|
|
65
66
|
export const enum QueryBuilderDataGridCustomAggregationFunction {
|
|
66
67
|
wavg = 'wavg',
|
|
@@ -87,13 +88,20 @@ const getAggregationTDSColumnCustomizations = (
|
|
|
87
88
|
filter: 'agDateColumnFilter',
|
|
88
89
|
allowedAggFuncs: ['count'],
|
|
89
90
|
};
|
|
90
|
-
case PRIMITIVE_TYPE.DECIMAL:
|
|
91
91
|
case PRIMITIVE_TYPE.NUMBER:
|
|
92
92
|
case PRIMITIVE_TYPE.INTEGER:
|
|
93
|
+
return {
|
|
94
|
+
filter: 'agNumberColumnFilter',
|
|
95
|
+
allowedAggFuncs: ['count', 'sum', 'max', 'min', 'avg', 'wavg'],
|
|
96
|
+
};
|
|
97
|
+
case PRIMITIVE_TYPE.DECIMAL:
|
|
93
98
|
case PRIMITIVE_TYPE.FLOAT:
|
|
94
99
|
return {
|
|
95
100
|
filter: 'agNumberColumnFilter',
|
|
96
101
|
allowedAggFuncs: ['count', 'sum', 'max', 'min', 'avg', 'wavg'],
|
|
102
|
+
headerComponentParams: {
|
|
103
|
+
template: getFloatGridColumnCustomHeader(columnName),
|
|
104
|
+
},
|
|
97
105
|
};
|
|
98
106
|
default:
|
|
99
107
|
return {
|
|
@@ -102,42 +110,6 @@ const getAggregationTDSColumnCustomizations = (
|
|
|
102
110
|
}
|
|
103
111
|
};
|
|
104
112
|
|
|
105
|
-
const getLocalColDefs = (
|
|
106
|
-
executionResult: TDSExecutionResult,
|
|
107
|
-
resultState: QueryBuilderResultState,
|
|
108
|
-
): DataGridColumnDefinition<
|
|
109
|
-
QueryBuilderTDSRowDataType,
|
|
110
|
-
QueryBuilderTDSResultCellDataType
|
|
111
|
-
>[] =>
|
|
112
|
-
executionResult.result.columns.map((colName) => {
|
|
113
|
-
const col = {
|
|
114
|
-
minWidth: 50,
|
|
115
|
-
sortable: true,
|
|
116
|
-
resizable: true,
|
|
117
|
-
field: colName,
|
|
118
|
-
flex: 1,
|
|
119
|
-
enablePivot: true,
|
|
120
|
-
enableRowGroup: true,
|
|
121
|
-
enableValue: true,
|
|
122
|
-
...getAggregationTDSColumnCustomizations(executionResult, colName),
|
|
123
|
-
} as DataGridColumnDefinition;
|
|
124
|
-
const persistedColumn = resultState.gridConfig?.columns.find(
|
|
125
|
-
(c) => c.colId === colName,
|
|
126
|
-
);
|
|
127
|
-
if (persistedColumn) {
|
|
128
|
-
if (persistedColumn.width) {
|
|
129
|
-
col.width = persistedColumn.width;
|
|
130
|
-
}
|
|
131
|
-
col.pinned = persistedColumn.pinned ?? null;
|
|
132
|
-
col.rowGroup = persistedColumn.rowGroup ?? false;
|
|
133
|
-
col.rowGroupIndex = persistedColumn.rowGroupIndex ?? null;
|
|
134
|
-
col.aggFunc = persistedColumn.aggFunc ?? null;
|
|
135
|
-
col.pivot = persistedColumn.pivot ?? false;
|
|
136
|
-
col.hide = persistedColumn.hide ?? false;
|
|
137
|
-
}
|
|
138
|
-
return col;
|
|
139
|
-
});
|
|
140
|
-
|
|
141
113
|
const QueryResultCellRenderer = observer(
|
|
142
114
|
(params: IQueryRendererParamsWithGridType) => {
|
|
143
115
|
const resultState = params.resultState;
|
|
@@ -186,6 +158,47 @@ const QueryResultCellRenderer = observer(
|
|
|
186
158
|
},
|
|
187
159
|
);
|
|
188
160
|
|
|
161
|
+
const getLocalColDefs = (
|
|
162
|
+
executionResult: TDSExecutionResult,
|
|
163
|
+
resultState: QueryBuilderResultState,
|
|
164
|
+
): DataGridColumnDefinition<
|
|
165
|
+
QueryBuilderTDSRowDataType,
|
|
166
|
+
QueryBuilderTDSResultCellDataType
|
|
167
|
+
>[] =>
|
|
168
|
+
executionResult.result.columns.map((colName) => {
|
|
169
|
+
const col = {
|
|
170
|
+
minWidth: 50,
|
|
171
|
+
sortable: true,
|
|
172
|
+
resizable: true,
|
|
173
|
+
field: colName,
|
|
174
|
+
flex: 1,
|
|
175
|
+
enablePivot: true,
|
|
176
|
+
enableRowGroup: true,
|
|
177
|
+
enableValue: true,
|
|
178
|
+
cellRenderer: QueryResultCellRenderer,
|
|
179
|
+
cellRendererParams: {
|
|
180
|
+
resultState: resultState,
|
|
181
|
+
tdsExecutionResult: executionResult,
|
|
182
|
+
},
|
|
183
|
+
...getAggregationTDSColumnCustomizations(executionResult, colName),
|
|
184
|
+
} as DataGridColumnDefinition;
|
|
185
|
+
const persistedColumn = resultState.gridConfig?.columns.find(
|
|
186
|
+
(c) => c.colId === colName,
|
|
187
|
+
);
|
|
188
|
+
if (persistedColumn) {
|
|
189
|
+
if (persistedColumn.width) {
|
|
190
|
+
col.width = persistedColumn.width;
|
|
191
|
+
}
|
|
192
|
+
col.pinned = persistedColumn.pinned ?? null;
|
|
193
|
+
col.rowGroup = persistedColumn.rowGroup ?? false;
|
|
194
|
+
col.rowGroupIndex = persistedColumn.rowGroupIndex ?? null;
|
|
195
|
+
col.aggFunc = persistedColumn.aggFunc ?? null;
|
|
196
|
+
col.pivot = persistedColumn.pivot ?? false;
|
|
197
|
+
col.hide = persistedColumn.hide ?? false;
|
|
198
|
+
}
|
|
199
|
+
return col;
|
|
200
|
+
});
|
|
201
|
+
|
|
189
202
|
const getFilterTDSColumnCustomizations = (
|
|
190
203
|
result: TDSExecutionResult,
|
|
191
204
|
columnName: string,
|
|
@@ -202,11 +215,17 @@ const getFilterTDSColumnCustomizations = (
|
|
|
202
215
|
};
|
|
203
216
|
case PRIMITIVE_TYPE.DECIMAL:
|
|
204
217
|
case PRIMITIVE_TYPE.INTEGER:
|
|
205
|
-
case PRIMITIVE_TYPE.FLOAT:
|
|
206
218
|
case PRIMITIVE_TYPE.NUMBER:
|
|
207
219
|
return {
|
|
208
220
|
filter: 'agNumberColumnFilter',
|
|
209
221
|
};
|
|
222
|
+
case PRIMITIVE_TYPE.FLOAT:
|
|
223
|
+
return {
|
|
224
|
+
filter: 'agNumberColumnFilter',
|
|
225
|
+
headerComponentParams: {
|
|
226
|
+
template: getFloatGridColumnCustomHeader(columnName),
|
|
227
|
+
},
|
|
228
|
+
};
|
|
210
229
|
default:
|
|
211
230
|
// we default all other columns to use filter true which defaults to set filters
|
|
212
231
|
return {
|
|
@@ -19,6 +19,7 @@ import { observer } from 'mobx-react-lite';
|
|
|
19
19
|
import type { QueryBuilderState } from '../../../stores/QueryBuilderState.js';
|
|
20
20
|
import {
|
|
21
21
|
getTDSRowRankByColumnInAsc,
|
|
22
|
+
PRIMITIVE_TYPE,
|
|
22
23
|
TDSExecutionResult,
|
|
23
24
|
} from '@finos/legend-graph';
|
|
24
25
|
import {
|
|
@@ -47,6 +48,47 @@ import type {
|
|
|
47
48
|
} from '../../../stores/QueryBuilderResultState.js';
|
|
48
49
|
import { QUERY_BUILDER_TEST_ID } from '../../../__lib__/QueryBuilderTesting.js';
|
|
49
50
|
|
|
51
|
+
export const getFloatGridColumnCustomHeader = (
|
|
52
|
+
columnName: string,
|
|
53
|
+
): string => ` <div data-testid="query__builder__result__grid__custom-header" class="query-builder__result__values__table__custom-header">
|
|
54
|
+
<div>${columnName}</div>
|
|
55
|
+
<div
|
|
56
|
+
class="query-builder__result__stale-status__icon"
|
|
57
|
+
title="some values have been rounded using en-us format in this preview grid (defaults to max 4 decimal places)"
|
|
58
|
+
>
|
|
59
|
+
<svg
|
|
60
|
+
stroke="currentColor"
|
|
61
|
+
fill="currentColor"
|
|
62
|
+
stroke-width="0"
|
|
63
|
+
viewBox="0 0 576 512"
|
|
64
|
+
height="1em"
|
|
65
|
+
width="1em"
|
|
66
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
67
|
+
>
|
|
68
|
+
<path d="M569.517 440.013C587.975 472.007 564.806 512 527.94 512H48.054c-36.937 0-59.999-40.055-41.577-71.987L246.423 23.985c18.467-32.009 64.72-31.951 83.154 0l239.94 416.028zM288 354c-25.405 0-46 20.595-46 46s20.595 46 46 46 46-20.595 46-46-20.595-46-46-46zm-43.673-165.346l7.418 136c.347 6.364 5.609 11.346 11.982 11.346h48.546c6.373 0 11.635-4.982 11.982-11.346l7.418-136c.375-6.874-5.098-12.654-11.982-12.654h-63.383c-6.884 0-12.356 5.78-11.981 12.654z"></path>
|
|
69
|
+
</svg>
|
|
70
|
+
</div>
|
|
71
|
+
</div>`;
|
|
72
|
+
|
|
73
|
+
const getTDSColumnCustomizations = (
|
|
74
|
+
result: TDSExecutionResult,
|
|
75
|
+
columnName: string,
|
|
76
|
+
): object => {
|
|
77
|
+
const columnType = result.builder.columns.find(
|
|
78
|
+
(col) => col.name === columnName,
|
|
79
|
+
)?.type;
|
|
80
|
+
switch (columnType) {
|
|
81
|
+
case PRIMITIVE_TYPE.FLOAT:
|
|
82
|
+
return {
|
|
83
|
+
headerComponentParams: {
|
|
84
|
+
template: getFloatGridColumnCustomHeader(columnName),
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
default:
|
|
88
|
+
return {};
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
|
|
50
92
|
const QueryResultCellRenderer = observer(
|
|
51
93
|
(params: IQueryRendererParamsWithGridType) => {
|
|
52
94
|
const resultState = params.resultState;
|
|
@@ -368,6 +410,7 @@ export const QueryBuilderTDSSimpleGridResult = observer(
|
|
|
368
410
|
resizable: true,
|
|
369
411
|
field: colName,
|
|
370
412
|
flex: 1,
|
|
413
|
+
...getTDSColumnCustomizations(executionResult, colName),
|
|
371
414
|
cellRenderer: QueryResultCellRenderer,
|
|
372
415
|
cellRendererParams: {
|
|
373
416
|
resultState: resultState,
|
|
@@ -28,6 +28,10 @@ import {
|
|
|
28
28
|
QUERY_BUILDER_VARIABLE_DND_TYPE,
|
|
29
29
|
type QueryBuilderVariableDragSource,
|
|
30
30
|
} from './BasicValueSpecificationEditor.js';
|
|
31
|
+
import {
|
|
32
|
+
QUERY_BUILDER_WINDOW_COLUMN_DND_TYPE,
|
|
33
|
+
type QueryBuilderWindowColumnDragSource,
|
|
34
|
+
} from '../../stores/fetch-structure/tds/window/QueryBuilderWindowState.js';
|
|
31
35
|
|
|
32
36
|
export const getDNDItemType = (
|
|
33
37
|
item: QueryBuilderFilterValueDropTarget,
|
|
@@ -45,6 +49,10 @@ export const getDNDItemType = (
|
|
|
45
49
|
case QUERY_BUILDER_VARIABLE_DND_TYPE:
|
|
46
50
|
return (item as QueryBuilderVariableDragSource).variable.genericType
|
|
47
51
|
?.value.rawType;
|
|
52
|
+
case QUERY_BUILDER_WINDOW_COLUMN_DND_TYPE:
|
|
53
|
+
return (
|
|
54
|
+
item as QueryBuilderWindowColumnDragSource
|
|
55
|
+
).columnState.getColumnType();
|
|
48
56
|
default:
|
|
49
57
|
return undefined;
|
|
50
58
|
}
|
|
@@ -117,7 +117,7 @@ export const QueryBuilderTaggedValueInfoTooltip: React.FC<{
|
|
|
117
117
|
);
|
|
118
118
|
};
|
|
119
119
|
|
|
120
|
-
const QueryBuilderBaseInfoTooltip: React.FC<{
|
|
120
|
+
export const QueryBuilderBaseInfoTooltip: React.FC<{
|
|
121
121
|
title: string;
|
|
122
122
|
data: {
|
|
123
123
|
label: string;
|
|
@@ -133,7 +133,10 @@ const QueryBuilderBaseInfoTooltip: React.FC<{
|
|
|
133
133
|
const [open, setIsOpen] = useState(false);
|
|
134
134
|
|
|
135
135
|
return (
|
|
136
|
-
<ClickAwayListener
|
|
136
|
+
<ClickAwayListener
|
|
137
|
+
onClickAway={() => setIsOpen(false)}
|
|
138
|
+
mouseEvent="onMouseDown"
|
|
139
|
+
>
|
|
137
140
|
<div>
|
|
138
141
|
<Tooltip
|
|
139
142
|
arrow={true}
|
|
@@ -172,7 +175,14 @@ const QueryBuilderBaseInfoTooltip: React.FC<{
|
|
|
172
175
|
</div>
|
|
173
176
|
}
|
|
174
177
|
>
|
|
175
|
-
<div
|
|
178
|
+
<div
|
|
179
|
+
onClick={(event: React.MouseEvent) => {
|
|
180
|
+
setIsOpen(!open);
|
|
181
|
+
event.stopPropagation();
|
|
182
|
+
}}
|
|
183
|
+
>
|
|
184
|
+
{children}
|
|
185
|
+
</div>
|
|
176
186
|
</Tooltip>
|
|
177
187
|
</div>
|
|
178
188
|
</ClickAwayListener>
|
|
@@ -33,11 +33,17 @@ export class QueryBuilderConfig {
|
|
|
33
33
|
*/
|
|
34
34
|
legendAIServiceURL = '';
|
|
35
35
|
|
|
36
|
+
/**
|
|
37
|
+
* This is the URL of the zipkin trace
|
|
38
|
+
*/
|
|
39
|
+
zipkinTraceBaseURL = '';
|
|
40
|
+
|
|
36
41
|
static readonly serialization = new SerializationFactory(
|
|
37
42
|
createModelSchema(QueryBuilderConfig, {
|
|
38
43
|
TEMPORARY__disableQueryBuilderChat: optional(primitive()),
|
|
39
44
|
TEMPORARY__enableGridEnterpriseMode: optional(primitive()),
|
|
40
45
|
legendAIServiceURL: optional(primitive()),
|
|
46
|
+
zipkinTraceBaseURL: optional(primitive()),
|
|
41
47
|
}),
|
|
42
48
|
);
|
|
43
49
|
}
|
|
@@ -17,10 +17,10 @@
|
|
|
17
17
|
import { action, flow, makeObservable, observable } from 'mobx';
|
|
18
18
|
import {
|
|
19
19
|
type GeneratorFn,
|
|
20
|
+
type ContentType,
|
|
20
21
|
assertErrorThrown,
|
|
21
22
|
LogEvent,
|
|
22
23
|
guaranteeNonNullable,
|
|
23
|
-
type ContentType,
|
|
24
24
|
ActionState,
|
|
25
25
|
StopWatch,
|
|
26
26
|
getContentTypeFileExtension,
|
|
@@ -32,11 +32,13 @@ import {
|
|
|
32
32
|
type RawLambda,
|
|
33
33
|
type EXECUTION_SERIALIZATION_FORMAT,
|
|
34
34
|
type QueryGridConfig,
|
|
35
|
+
type ExecutionResultWithMetadata,
|
|
35
36
|
GRAPH_MANAGER_EVENT,
|
|
36
37
|
buildRawLambdaFromLambdaFunction,
|
|
37
38
|
reportGraphAnalytics,
|
|
39
|
+
TDSExecutionResult,
|
|
40
|
+
V1_ZIPKIN_TRACE_HEADER,
|
|
38
41
|
} from '@finos/legend-graph';
|
|
39
|
-
|
|
40
42
|
import { buildLambdaFunction } from './QueryBuilderValueSpecificationBuilder.js';
|
|
41
43
|
import {
|
|
42
44
|
buildExecutionParameterValues,
|
|
@@ -49,6 +51,7 @@ import { ExecutionPlanState } from './execution-plan/ExecutionPlanState.js';
|
|
|
49
51
|
import type { DataGridColumnState } from '@finos/legend-lego/data-grid';
|
|
50
52
|
import { downloadStream } from '@finos/legend-application';
|
|
51
53
|
import { QueryBuilderDataGridCustomAggregationFunction } from '../components/result/tds/QueryBuilderTDSGridResult.js';
|
|
54
|
+
import { QueryBuilderTDSState } from './fetch-structure/tds/QueryBuilderTDSState.js';
|
|
52
55
|
|
|
53
56
|
export const DEFAULT_LIMIT = 1000;
|
|
54
57
|
|
|
@@ -125,10 +128,13 @@ export class QueryBuilderResultState {
|
|
|
125
128
|
isRunningQuery = false;
|
|
126
129
|
isGeneratingPlan = false;
|
|
127
130
|
executionResult?: ExecutionResult | undefined;
|
|
131
|
+
isExecutionResultOverflowing = false;
|
|
128
132
|
executionDuration?: number | undefined;
|
|
133
|
+
executionTraceId?: string;
|
|
129
134
|
latestRunHashCode?: string | undefined;
|
|
130
|
-
queryRunPromise: Promise<
|
|
135
|
+
queryRunPromise: Promise<ExecutionResultWithMetadata> | undefined = undefined;
|
|
131
136
|
isQueryUsageViewerOpened = false;
|
|
137
|
+
executionError: Error | string | undefined;
|
|
132
138
|
|
|
133
139
|
selectedCells: QueryBuilderTDSResultCellData[];
|
|
134
140
|
mousedOverCell: QueryBuilderTDSResultCellData | null = null;
|
|
@@ -140,6 +146,7 @@ export class QueryBuilderResultState {
|
|
|
140
146
|
constructor(queryBuilderState: QueryBuilderState) {
|
|
141
147
|
makeObservable(this, {
|
|
142
148
|
executionResult: observable,
|
|
149
|
+
executionTraceId: observable,
|
|
143
150
|
previewLimit: observable,
|
|
144
151
|
executionDuration: observable,
|
|
145
152
|
latestRunHashCode: observable,
|
|
@@ -150,13 +157,16 @@ export class QueryBuilderResultState {
|
|
|
150
157
|
isRunningQuery: observable,
|
|
151
158
|
isSelectingCells: observable,
|
|
152
159
|
isQueryUsageViewerOpened: observable,
|
|
160
|
+
isExecutionResultOverflowing: observable,
|
|
153
161
|
gridConfig: observable,
|
|
154
162
|
wavgAggregationState: observable,
|
|
163
|
+
executionError: observable,
|
|
155
164
|
setGridConfig: action,
|
|
156
165
|
setWavgAggregationState: action,
|
|
157
166
|
setIsSelectingCells: action,
|
|
158
167
|
setIsRunningQuery: action,
|
|
159
168
|
setExecutionResult: action,
|
|
169
|
+
setExecutionTraceId: action,
|
|
160
170
|
setExecutionDuration: action,
|
|
161
171
|
setPreviewLimit: action,
|
|
162
172
|
addSelectedCell: action,
|
|
@@ -164,8 +174,10 @@ export class QueryBuilderResultState {
|
|
|
164
174
|
setMouseOverCell: action,
|
|
165
175
|
setQueryRunPromise: action,
|
|
166
176
|
setIsQueryUsageViewerOpened: action,
|
|
177
|
+
setIsExecutionResultOverflowing: action,
|
|
167
178
|
handlePreConfiguredGridConfig: action,
|
|
168
179
|
updatePreviewLimitInConfig: action,
|
|
180
|
+
setExecutionError: action,
|
|
169
181
|
exportData: flow,
|
|
170
182
|
runQuery: flow,
|
|
171
183
|
cancelQuery: flow,
|
|
@@ -204,6 +216,10 @@ export class QueryBuilderResultState {
|
|
|
204
216
|
this.executionResult = val;
|
|
205
217
|
}
|
|
206
218
|
|
|
219
|
+
setExecutionTraceId(val: string): void {
|
|
220
|
+
this.executionTraceId = val;
|
|
221
|
+
}
|
|
222
|
+
|
|
207
223
|
setExecutionDuration(val: number | undefined): void {
|
|
208
224
|
this.executionDuration = val;
|
|
209
225
|
}
|
|
@@ -224,7 +240,9 @@ export class QueryBuilderResultState {
|
|
|
224
240
|
this.mousedOverCell = val;
|
|
225
241
|
}
|
|
226
242
|
|
|
227
|
-
setQueryRunPromise(
|
|
243
|
+
setQueryRunPromise(
|
|
244
|
+
promise: Promise<ExecutionResultWithMetadata> | undefined,
|
|
245
|
+
): void {
|
|
228
246
|
this.queryRunPromise = promise;
|
|
229
247
|
}
|
|
230
248
|
|
|
@@ -232,12 +250,44 @@ export class QueryBuilderResultState {
|
|
|
232
250
|
this.isQueryUsageViewerOpened = val;
|
|
233
251
|
}
|
|
234
252
|
|
|
253
|
+
setExecutionError(val: Error | string | undefined): void {
|
|
254
|
+
this.executionError = val;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
setIsExecutionResultOverflowing(val: boolean): void {
|
|
258
|
+
this.isExecutionResultOverflowing = val;
|
|
259
|
+
}
|
|
260
|
+
|
|
235
261
|
updatePreviewLimitInConfig(): void {
|
|
236
262
|
if (this.gridConfig) {
|
|
237
263
|
this.gridConfig.previewLimit = this.previewLimit;
|
|
238
264
|
}
|
|
239
265
|
}
|
|
240
266
|
|
|
267
|
+
getExecutionResultLimit = (): number =>
|
|
268
|
+
Math.min(
|
|
269
|
+
this.queryBuilderState.fetchStructureState.implementation instanceof
|
|
270
|
+
QueryBuilderTDSState &&
|
|
271
|
+
this.queryBuilderState.fetchStructureState.implementation
|
|
272
|
+
.resultSetModifierState.limit
|
|
273
|
+
? this.queryBuilderState.fetchStructureState.implementation
|
|
274
|
+
.resultSetModifierState.limit
|
|
275
|
+
: Number.MAX_SAFE_INTEGER,
|
|
276
|
+
this.previewLimit,
|
|
277
|
+
);
|
|
278
|
+
|
|
279
|
+
processExecutionResult = (result: ExecutionResult): void => {
|
|
280
|
+
this.setIsExecutionResultOverflowing(false);
|
|
281
|
+
if (result instanceof TDSExecutionResult) {
|
|
282
|
+
const resultLimit = this.getExecutionResultLimit();
|
|
283
|
+
if (result.result.rows.length > resultLimit) {
|
|
284
|
+
this.setIsExecutionResultOverflowing(true);
|
|
285
|
+
result.result.rows = result.result.rows.slice(0, resultLimit);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
this.setExecutionResult(result);
|
|
289
|
+
};
|
|
290
|
+
|
|
241
291
|
processWeightedColumnPairsMap(
|
|
242
292
|
config: QueryGridConfig,
|
|
243
293
|
): Map<string, string> | undefined {
|
|
@@ -421,7 +471,9 @@ export class QueryBuilderResultState {
|
|
|
421
471
|
this.queryBuilderState.executionContextState.runtimeValue,
|
|
422
472
|
`Runtime is required to execute query`,
|
|
423
473
|
);
|
|
424
|
-
const query = this.buildExecutionRawLambda(
|
|
474
|
+
const query = this.buildExecutionRawLambda({
|
|
475
|
+
withDataOverflowCheck: true,
|
|
476
|
+
});
|
|
425
477
|
const parameterValues = buildExecutionParameterValues(
|
|
426
478
|
this.queryBuilderState.parametersState.parameterStates,
|
|
427
479
|
this.queryBuilderState.graphManagerState,
|
|
@@ -444,13 +496,17 @@ export class QueryBuilderResultState {
|
|
|
444
496
|
{
|
|
445
497
|
parameterValues,
|
|
446
498
|
convertUnsafeNumbersToString: true,
|
|
499
|
+
preservedResponseHeadersList: [V1_ZIPKIN_TRACE_HEADER],
|
|
447
500
|
},
|
|
448
501
|
);
|
|
449
502
|
|
|
450
503
|
this.setQueryRunPromise(promise);
|
|
451
|
-
const result = (yield promise) as
|
|
504
|
+
const result = (yield promise) as ExecutionResultWithMetadata;
|
|
452
505
|
if (this.queryRunPromise === promise) {
|
|
453
|
-
this.
|
|
506
|
+
this.processExecutionResult(result.executionResult);
|
|
507
|
+
if (result.executionTraceId) {
|
|
508
|
+
this.setExecutionTraceId(result.executionTraceId);
|
|
509
|
+
}
|
|
454
510
|
this.latestRunHashCode = currentHashCode;
|
|
455
511
|
this.setExecutionDuration(stopWatch.elapsed);
|
|
456
512
|
|
|
@@ -479,9 +535,7 @@ export class QueryBuilderResultState {
|
|
|
479
535
|
LogEvent.create(GRAPH_MANAGER_EVENT.EXECUTION_FAILURE),
|
|
480
536
|
error,
|
|
481
537
|
);
|
|
482
|
-
this.
|
|
483
|
-
error,
|
|
484
|
-
);
|
|
538
|
+
this.setExecutionError(error);
|
|
485
539
|
}
|
|
486
540
|
} finally {
|
|
487
541
|
this.setIsRunningQuery(false);
|
|
@@ -210,4 +210,9 @@ export type LambdaFunctionBuilderOption = {
|
|
|
210
210
|
* typed in engine. This is still an experimental feature, hence we should only enable this flag when user wants to enable this directly.
|
|
211
211
|
*/
|
|
212
212
|
useTypedRelationFunctions?: boolean | undefined;
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Set this flag to `true` when you want to execute a query that exceeds the limit to check for additional data in the database.
|
|
216
|
+
*/
|
|
217
|
+
withDataOverflowCheck?: boolean | undefined;
|
|
213
218
|
};
|
|
@@ -118,8 +118,10 @@ export abstract class QueryBuilderExplorerTreeNodeData implements TreeNodeData {
|
|
|
118
118
|
) {
|
|
119
119
|
makeObservable(this, {
|
|
120
120
|
isHighlighting: observable,
|
|
121
|
+
isOpen: observable,
|
|
121
122
|
isSelected: observable,
|
|
122
123
|
setIsHighlighting: action,
|
|
124
|
+
setIsOpen: action,
|
|
123
125
|
setIsSelected: action,
|
|
124
126
|
});
|
|
125
127
|
|
|
@@ -136,6 +138,10 @@ export abstract class QueryBuilderExplorerTreeNodeData implements TreeNodeData {
|
|
|
136
138
|
this.isSelected = val;
|
|
137
139
|
}
|
|
138
140
|
|
|
141
|
+
setIsOpen(val: boolean | undefined): void {
|
|
142
|
+
this.isOpen = val;
|
|
143
|
+
}
|
|
144
|
+
|
|
139
145
|
setIsHighlighting(val: boolean | undefined): void {
|
|
140
146
|
this.isHighlighting = val;
|
|
141
147
|
}
|
|
@@ -650,15 +656,18 @@ export class QueryBuilderExplorerPreviewDataState {
|
|
|
650
656
|
isGeneratingPreviewData = false;
|
|
651
657
|
propertyName = '(unknown)';
|
|
652
658
|
previewData?: QueryBuilderPreviewData | undefined;
|
|
659
|
+
previewDataAbortController?: AbortController | undefined;
|
|
653
660
|
|
|
654
661
|
constructor() {
|
|
655
662
|
makeObservable(this, {
|
|
656
663
|
previewData: observable.ref,
|
|
657
664
|
isGeneratingPreviewData: observable,
|
|
658
665
|
propertyName: observable,
|
|
666
|
+
previewDataAbortController: observable,
|
|
659
667
|
setPropertyName: action,
|
|
660
668
|
setIsGeneratingPreviewData: action,
|
|
661
669
|
setPreviewData: action,
|
|
670
|
+
setPreviewDataAbortController: action,
|
|
662
671
|
});
|
|
663
672
|
}
|
|
664
673
|
|
|
@@ -673,6 +682,10 @@ export class QueryBuilderExplorerPreviewDataState {
|
|
|
673
682
|
setPreviewData(val: QueryBuilderPreviewData | undefined): void {
|
|
674
683
|
this.previewData = val;
|
|
675
684
|
}
|
|
685
|
+
|
|
686
|
+
setPreviewDataAbortController(val: AbortController | undefined): void {
|
|
687
|
+
this.previewDataAbortController = val;
|
|
688
|
+
}
|
|
676
689
|
}
|
|
677
690
|
|
|
678
691
|
export class QueryBuilderExplorerState {
|
|
@@ -754,21 +767,99 @@ export class QueryBuilderExplorerState {
|
|
|
754
767
|
);
|
|
755
768
|
}
|
|
756
769
|
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
770
|
+
generateOpenNodeChildren(node: QueryBuilderExplorerTreeNodeData): void {
|
|
771
|
+
if (
|
|
772
|
+
node.isOpen &&
|
|
773
|
+
(node instanceof QueryBuilderExplorerTreePropertyNodeData ||
|
|
774
|
+
node instanceof QueryBuilderExplorerTreeSubTypeNodeData) &&
|
|
775
|
+
node.type instanceof Class
|
|
776
|
+
) {
|
|
777
|
+
(node instanceof QueryBuilderExplorerTreeSubTypeNodeData
|
|
778
|
+
? getAllOwnClassProperties(node.type)
|
|
779
|
+
: getAllClassProperties(node.type).concat(
|
|
780
|
+
getAllClassDerivedProperties(node.type),
|
|
781
|
+
)
|
|
782
|
+
).forEach((property) => {
|
|
783
|
+
const propertyTreeNodeData = getQueryBuilderPropertyNodeData(
|
|
784
|
+
property,
|
|
785
|
+
node,
|
|
786
|
+
guaranteeNonNullable(this.mappingModelCoverageAnalysisResult),
|
|
787
|
+
);
|
|
788
|
+
if (propertyTreeNodeData) {
|
|
789
|
+
this.nonNullableTreeData.nodes.set(
|
|
790
|
+
propertyTreeNodeData.id,
|
|
791
|
+
propertyTreeNodeData,
|
|
792
|
+
);
|
|
793
|
+
}
|
|
794
|
+
});
|
|
795
|
+
node.type._subclasses.forEach((subclass) => {
|
|
796
|
+
const subTypeTreeNodeData = getQueryBuilderSubTypeNodeData(
|
|
797
|
+
subclass,
|
|
798
|
+
node,
|
|
799
|
+
guaranteeNonNullable(this.mappingModelCoverageAnalysisResult),
|
|
800
|
+
);
|
|
801
|
+
this.nonNullableTreeData.nodes.set(
|
|
802
|
+
subTypeTreeNodeData.id,
|
|
803
|
+
subTypeTreeNodeData,
|
|
804
|
+
);
|
|
805
|
+
});
|
|
806
|
+
this.refreshTree();
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
highlightTreeNode(nodeId: string): void {
|
|
811
|
+
// If the node doesn't yet exist in the explorer tree,
|
|
812
|
+
// we need to open all the parent nodes of the node and
|
|
813
|
+
// generate their children.
|
|
814
|
+
if (this.nonNullableTreeData.nodes.get(nodeId) === undefined) {
|
|
815
|
+
const parentNodeIdElements: string[][] = nodeId
|
|
816
|
+
.split('@')
|
|
817
|
+
.map((subpath) => subpath.split('.'));
|
|
818
|
+
// remove last element of final subpath, as it is the node id and not a parent
|
|
819
|
+
if (
|
|
820
|
+
parentNodeIdElements.length > 0 &&
|
|
821
|
+
parentNodeIdElements[parentNodeIdElements.length - 1] !== undefined
|
|
822
|
+
) {
|
|
823
|
+
parentNodeIdElements[parentNodeIdElements.length - 1]!.pop();
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
let currentNodeId = '';
|
|
827
|
+
|
|
828
|
+
parentNodeIdElements.forEach((subpath) => {
|
|
829
|
+
subpath.forEach((element, index) => {
|
|
830
|
+
currentNodeId += `${index > 0 ? '.' : ''}${element}`;
|
|
831
|
+
const currentNode = this.nonNullableTreeData.nodes.get(currentNodeId);
|
|
832
|
+
if (currentNode) {
|
|
833
|
+
currentNode.setIsOpen(true);
|
|
834
|
+
this.generateOpenNodeChildren(currentNode);
|
|
835
|
+
}
|
|
836
|
+
});
|
|
837
|
+
currentNodeId += '@';
|
|
838
|
+
});
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
// All parent nodes should be created now, so we can get the node to highlight.
|
|
842
|
+
const nodeToHighlight = this.nonNullableTreeData.nodes.get(nodeId);
|
|
843
|
+
|
|
844
|
+
// If we didn't need to open and create the parent nodes above, we will
|
|
845
|
+
// open the parent nodes here in case they are closed. Then, we will highlight
|
|
846
|
+
// and scroll to the node.
|
|
847
|
+
if (
|
|
848
|
+
nodeToHighlight instanceof QueryBuilderExplorerTreePropertyNodeData ||
|
|
849
|
+
nodeToHighlight instanceof QueryBuilderExplorerTreeSubTypeNodeData
|
|
850
|
+
) {
|
|
760
851
|
let nodeToOpen: QueryBuilderExplorerTreeNodeData | null =
|
|
761
|
-
this.
|
|
852
|
+
this.nonNullableTreeData.nodes.get(nodeToHighlight.parentId) ?? null;
|
|
762
853
|
while (nodeToOpen !== null) {
|
|
763
854
|
if (!nodeToOpen.isOpen) {
|
|
764
|
-
nodeToOpen.
|
|
855
|
+
nodeToOpen.setIsOpen(true);
|
|
765
856
|
}
|
|
766
857
|
nodeToOpen =
|
|
767
|
-
nodeToOpen instanceof QueryBuilderExplorerTreePropertyNodeData
|
|
768
|
-
|
|
858
|
+
nodeToOpen instanceof QueryBuilderExplorerTreePropertyNodeData ||
|
|
859
|
+
nodeToOpen instanceof QueryBuilderExplorerTreeSubTypeNodeData
|
|
860
|
+
? (this.nonNullableTreeData.nodes.get(nodeToOpen.parentId) ?? null)
|
|
769
861
|
: null;
|
|
770
862
|
}
|
|
771
|
-
this.refreshTree();
|
|
772
863
|
nodeToHighlight.setIsHighlighting(true);
|
|
773
864
|
// scrollIntoView must be called in a setTimeout because it must happen after
|
|
774
865
|
// the tree nodes are recursively opened and the tree is refreshed.
|
|
@@ -859,6 +950,7 @@ export class QueryBuilderExplorerState {
|
|
|
859
950
|
this,
|
|
860
951
|
);
|
|
861
952
|
const propertyType = node.property.genericType.value.rawType;
|
|
953
|
+
this.previewDataState.setPreviewDataAbortController(new AbortController());
|
|
862
954
|
try {
|
|
863
955
|
switch (propertyType.path) {
|
|
864
956
|
case PRIMITIVE_TYPE.NUMBER:
|
|
@@ -874,6 +966,10 @@ export class QueryBuilderExplorerState {
|
|
|
874
966
|
this.queryBuilderState.executionContextState.mapping,
|
|
875
967
|
runtime,
|
|
876
968
|
this.queryBuilderState.graphManagerState.graph,
|
|
969
|
+
{
|
|
970
|
+
abortController:
|
|
971
|
+
this.previewDataState.previewDataAbortController,
|
|
972
|
+
},
|
|
877
973
|
)) as ExecutionResult;
|
|
878
974
|
assertType(
|
|
879
975
|
previewResult,
|
|
@@ -911,6 +1007,10 @@ export class QueryBuilderExplorerState {
|
|
|
911
1007
|
this.queryBuilderState.executionContextState.mapping,
|
|
912
1008
|
runtime,
|
|
913
1009
|
this.queryBuilderState.graphManagerState.graph,
|
|
1010
|
+
{
|
|
1011
|
+
abortController:
|
|
1012
|
+
this.previewDataState.previewDataAbortController,
|
|
1013
|
+
},
|
|
914
1014
|
)) as ExecutionResult;
|
|
915
1015
|
assertType(
|
|
916
1016
|
previewResult,
|
|
@@ -929,12 +1029,16 @@ export class QueryBuilderExplorerState {
|
|
|
929
1029
|
}
|
|
930
1030
|
} catch (error) {
|
|
931
1031
|
assertErrorThrown(error);
|
|
1032
|
+
if (error.name === 'AbortError') {
|
|
1033
|
+
return;
|
|
1034
|
+
}
|
|
932
1035
|
this.queryBuilderState.applicationStore.notificationService.notifyWarning(
|
|
933
1036
|
`Can't preview data for property '${node.property.name}'. Error: ${error.message}`,
|
|
934
1037
|
);
|
|
935
1038
|
this.previewDataState.setPreviewData(undefined);
|
|
936
1039
|
} finally {
|
|
937
1040
|
this.previewDataState.setIsGeneratingPreviewData(false);
|
|
1041
|
+
this.previewDataState.setPreviewDataAbortController(undefined);
|
|
938
1042
|
}
|
|
939
1043
|
}
|
|
940
1044
|
}
|