@finos/legend-query-builder 4.0.9 → 4.0.11
Sign up to get free protection for your applications and to get access to all the features.
- package/lib/components/QueryBuilderResultPanel.d.ts.map +1 -1
- package/lib/components/QueryBuilderResultPanel.js +208 -67
- package/lib/components/QueryBuilderResultPanel.js.map +1 -1
- package/lib/index.css +1 -17
- package/lib/index.css.map +1 -1
- package/lib/package.json +6 -6
- package/lib/stores/QueryBuilderResultState.d.ts +19 -0
- package/lib/stores/QueryBuilderResultState.d.ts.map +1 -1
- package/lib/stores/QueryBuilderResultState.js +48 -1
- package/lib/stores/QueryBuilderResultState.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.map +1 -1
- package/lib/stores/shared/LambdaParameterState.d.ts.map +1 -1
- package/lib/stores/shared/LambdaParameterState.js +1 -1
- package/lib/stores/shared/LambdaParameterState.js.map +1 -1
- package/lib/stores/shared/ValueSpecificationEditorHelper.d.ts +5 -2
- package/lib/stores/shared/ValueSpecificationEditorHelper.d.ts.map +1 -1
- package/lib/stores/shared/ValueSpecificationEditorHelper.js +30 -40
- package/lib/stores/shared/ValueSpecificationEditorHelper.js.map +1 -1
- package/package.json +14 -14
- package/src/components/QueryBuilderResultPanel.tsx +357 -91
- package/src/stores/QueryBuilderResultState.ts +82 -0
- package/src/stores/fetch-structure/tds/post-filter/QueryBuilderPostFilterState.ts +1 -0
- package/src/stores/shared/LambdaParameterState.ts +1 -0
- package/src/stores/shared/ValueSpecificationEditorHelper.ts +80 -57
@@ -68,7 +68,7 @@ import {
|
|
68
68
|
prettyDuration,
|
69
69
|
filterByType,
|
70
70
|
} from '@finos/legend-shared';
|
71
|
-
import {
|
71
|
+
import { forwardRef, useState } from 'react';
|
72
72
|
import {
|
73
73
|
QueryBuilderDerivationProjectionColumnState,
|
74
74
|
QueryBuilderProjectionColumnState,
|
@@ -96,13 +96,22 @@ import { PARAMETER_SUBMIT_ACTION } from '../stores/shared/LambdaParameterState.j
|
|
96
96
|
import { QUERY_BUILDER_TEST_ID } from '../__lib__/QueryBuilderTesting.js';
|
97
97
|
import {
|
98
98
|
DataGrid,
|
99
|
-
type
|
99
|
+
type DataGridCellRendererParams,
|
100
100
|
} from '@finos/legend-lego/data-grid';
|
101
101
|
import {
|
102
102
|
CODE_EDITOR_LANGUAGE,
|
103
103
|
CodeEditor,
|
104
104
|
} from '@finos/legend-lego/code-editor';
|
105
105
|
import { ExecutionPlanViewer } from './execution-plan/ExecutionPlanViewer.js';
|
106
|
+
import type {
|
107
|
+
QueryBuilderTDSResultCellCoordinate,
|
108
|
+
QueryBuilderResultState,
|
109
|
+
QueryBuilderTDSResultCellData,
|
110
|
+
} from '../stores/QueryBuilderResultState.js';
|
111
|
+
import {
|
112
|
+
QueryBuilderPostFilterOperator_IsEmpty,
|
113
|
+
QueryBuilderPostFilterOperator_IsNotEmpty,
|
114
|
+
} from '../stores/fetch-structure/tds/post-filter/operators/QueryBuilderPostFilterOperator_IsEmpty.js';
|
106
115
|
|
107
116
|
export const tryToFormatSql = (sql: string): string => {
|
108
117
|
try {
|
@@ -117,7 +126,7 @@ const QueryBuilderGridResultContextMenu = observer(
|
|
117
126
|
forwardRef<
|
118
127
|
HTMLDivElement,
|
119
128
|
{
|
120
|
-
event:
|
129
|
+
event: QueryBuilderTDSResultCellData | null;
|
121
130
|
tdsState: QueryBuilderTDSState;
|
122
131
|
}
|
123
132
|
>(function QueryBuilderResultContextMenu(props, ref) {
|
@@ -125,20 +134,26 @@ const QueryBuilderGridResultContextMenu = observer(
|
|
125
134
|
const applicationStore = useApplicationStore();
|
126
135
|
const postFilterEqualOperator = new QueryBuilderPostFilterOperator_Equal();
|
127
136
|
const postFilterInOperator = new QueryBuilderPostFilterOperator_In();
|
137
|
+
const postFilterEmptyOperator =
|
138
|
+
new QueryBuilderPostFilterOperator_IsEmpty();
|
139
|
+
const postFilterNotEmptyOperator =
|
140
|
+
new QueryBuilderPostFilterOperator_IsNotEmpty();
|
141
|
+
|
128
142
|
const postFilterNotEqualOperator =
|
129
143
|
new QueryBuilderPostFilterOperator_NotEqual();
|
130
144
|
const postFilterNotInOperator = new QueryBuilderPostFilterOperator_NotIn();
|
131
145
|
const postFilterState = tdsState.postFilterState;
|
132
|
-
|
133
|
-
|
146
|
+
|
147
|
+
const projectionColumnState = tdsState.projectionColumns
|
148
|
+
.filter((c) => c.columnName === event?.columnName)
|
134
149
|
.concat(
|
135
150
|
tdsState.aggregationState.columns
|
136
|
-
.filter((c) => c.columnName === event
|
151
|
+
.filter((c) => c.columnName === event?.columnName)
|
137
152
|
.map((ag) => ag.projectionColumnState),
|
138
153
|
)[0];
|
139
|
-
|
140
154
|
const getExistingPostFilterNode = (
|
141
155
|
operators: QueryBuilderPostFilterOperator[],
|
156
|
+
projectionColumnName: string | undefined,
|
142
157
|
): QueryBuilderPostFilterTreeNodeData | undefined =>
|
143
158
|
Array.from(postFilterState.nodes.values())
|
144
159
|
.filter(
|
@@ -150,7 +165,8 @@ const QueryBuilderGridResultContextMenu = observer(
|
|
150
165
|
.filter(
|
151
166
|
(n) =>
|
152
167
|
(n as QueryBuilderPostFilterTreeConditionNodeData).condition
|
153
|
-
.columnState.columnName ===
|
168
|
+
.columnState.columnName ===
|
169
|
+
(projectionColumnName ?? projectionColumnState?.columnName) &&
|
154
170
|
operators
|
155
171
|
.map((op) => op.getLabel())
|
156
172
|
.includes(
|
@@ -162,8 +178,9 @@ const QueryBuilderGridResultContextMenu = observer(
|
|
162
178
|
|
163
179
|
const updateFilterConditionValue = (
|
164
180
|
conditionValue: InstanceValue,
|
181
|
+
cellData: QueryBuilderTDSResultCellData,
|
165
182
|
): void => {
|
166
|
-
if (
|
183
|
+
if (cellData.value) {
|
167
184
|
instanceValue_setValue(
|
168
185
|
conditionValue,
|
169
186
|
conditionValue instanceof EnumValueInstanceValue
|
@@ -172,10 +189,10 @@ const QueryBuilderGridResultContextMenu = observer(
|
|
172
189
|
(
|
173
190
|
conditionValue.genericType?.ownerReference
|
174
191
|
.value as Enumeration
|
175
|
-
).values.filter((v) => v.name ===
|
192
|
+
).values.filter((v) => v.name === cellData.value)[0],
|
176
193
|
),
|
177
194
|
)
|
178
|
-
:
|
195
|
+
: cellData.value,
|
179
196
|
0,
|
180
197
|
tdsState.queryBuilderState.observerContext,
|
181
198
|
);
|
@@ -184,15 +201,28 @@ const QueryBuilderGridResultContextMenu = observer(
|
|
184
201
|
|
185
202
|
const generateNewPostFilterConditionNodeData = async (
|
186
203
|
operator: QueryBuilderPostFilterOperator,
|
204
|
+
cellData: QueryBuilderTDSResultCellData,
|
187
205
|
): Promise<void> => {
|
188
|
-
|
189
|
-
|
190
|
-
|
206
|
+
let postFilterConditionState: PostFilterConditionState;
|
207
|
+
try {
|
208
|
+
const possibleProjectionColumnState = cellData.columnName
|
209
|
+
? tdsState.projectionColumns
|
210
|
+
.filter((c) => c.columnName === cellData.columnName)
|
211
|
+
.concat(
|
212
|
+
tdsState.aggregationState.columns
|
213
|
+
.filter((c) => c.columnName === cellData.columnName)
|
214
|
+
.map((ag) => ag.projectionColumnState),
|
215
|
+
)[0]
|
216
|
+
: projectionColumnState;
|
217
|
+
|
218
|
+
if (possibleProjectionColumnState) {
|
219
|
+
postFilterConditionState = new PostFilterConditionState(
|
191
220
|
postFilterState,
|
192
|
-
|
221
|
+
possibleProjectionColumnState,
|
193
222
|
undefined,
|
194
223
|
operator,
|
195
224
|
);
|
225
|
+
|
196
226
|
if (
|
197
227
|
projectionColumnState instanceof
|
198
228
|
QueryBuilderDerivationProjectionColumnState
|
@@ -201,13 +231,16 @@ const QueryBuilderGridResultContextMenu = observer(
|
|
201
231
|
projectionColumnState.fetchDerivationLambdaReturnType(),
|
202
232
|
);
|
203
233
|
}
|
234
|
+
|
204
235
|
const defaultFilterConditionValue =
|
205
236
|
postFilterConditionState.operator.getDefaultFilterConditionValue(
|
206
237
|
postFilterConditionState,
|
207
238
|
);
|
239
|
+
|
208
240
|
postFilterConditionState.setValue(defaultFilterConditionValue);
|
209
241
|
updateFilterConditionValue(
|
210
242
|
defaultFilterConditionValue as InstanceValue,
|
243
|
+
cellData,
|
211
244
|
);
|
212
245
|
postFilterState.addNodeFromNode(
|
213
246
|
new QueryBuilderPostFilterTreeConditionNodeData(
|
@@ -216,41 +249,56 @@ const QueryBuilderGridResultContextMenu = observer(
|
|
216
249
|
),
|
217
250
|
undefined,
|
218
251
|
);
|
219
|
-
} catch (error) {
|
220
|
-
assertErrorThrown(error);
|
221
|
-
applicationStore.notificationService.notifyWarning(error.message);
|
222
|
-
return;
|
223
252
|
}
|
253
|
+
} catch (error) {
|
254
|
+
assertErrorThrown(error);
|
255
|
+
applicationStore.notificationService.notifyWarning(error.message);
|
256
|
+
return;
|
224
257
|
}
|
225
258
|
};
|
226
259
|
|
227
260
|
const updateExistingPostFilterConditionNodeData = (
|
228
261
|
existingPostFilterNode: QueryBuilderPostFilterTreeNodeData,
|
229
262
|
isFilterBy: boolean,
|
263
|
+
cellData: QueryBuilderTDSResultCellData,
|
264
|
+
operator: QueryBuilderPostFilterOperator,
|
230
265
|
): void => {
|
266
|
+
if (
|
267
|
+
operator === postFilterEmptyOperator ||
|
268
|
+
operator === postFilterNotEmptyOperator
|
269
|
+
) {
|
270
|
+
const conditionState = (
|
271
|
+
existingPostFilterNode as QueryBuilderPostFilterTreeConditionNodeData
|
272
|
+
).condition;
|
273
|
+
if (conditionState.operator.getLabel() !== operator.getLabel()) {
|
274
|
+
conditionState.changeOperator(
|
275
|
+
isFilterBy ? postFilterEmptyOperator : postFilterNotEmptyOperator,
|
276
|
+
);
|
277
|
+
}
|
278
|
+
return;
|
279
|
+
}
|
231
280
|
const conditionState = (
|
232
281
|
existingPostFilterNode as QueryBuilderPostFilterTreeConditionNodeData
|
233
282
|
).condition;
|
234
|
-
|
235
|
-
|
236
|
-
(isFilterBy
|
237
|
-
? postFilterEqualOperator
|
238
|
-
: postFilterNotEqualOperator
|
239
|
-
).getLabel()
|
240
|
-
) {
|
283
|
+
|
284
|
+
if (conditionState.operator.getLabel() === operator.getLabel()) {
|
241
285
|
const doesValueAlreadyExist =
|
242
286
|
conditionState.value instanceof InstanceValue &&
|
243
287
|
(conditionState.value instanceof EnumValueInstanceValue
|
244
288
|
? conditionState.value.values.map((ef) => ef.value.name)
|
245
289
|
: conditionState.value.values
|
246
|
-
).includes(
|
290
|
+
).includes(cellData.value);
|
291
|
+
|
247
292
|
if (!doesValueAlreadyExist) {
|
248
293
|
const currentValueSpecificaton = conditionState.value;
|
249
294
|
const newValueSpecification =
|
250
295
|
conditionState.operator.getDefaultFilterConditionValue(
|
251
296
|
conditionState,
|
252
297
|
);
|
253
|
-
updateFilterConditionValue(
|
298
|
+
updateFilterConditionValue(
|
299
|
+
newValueSpecification as InstanceValue,
|
300
|
+
cellData,
|
301
|
+
);
|
254
302
|
conditionState.changeOperator(
|
255
303
|
isFilterBy ? postFilterInOperator : postFilterNotInOperator,
|
256
304
|
);
|
@@ -271,12 +319,16 @@ const QueryBuilderGridResultContextMenu = observer(
|
|
271
319
|
: (v as InstanceValue).values,
|
272
320
|
)
|
273
321
|
.flat()
|
274
|
-
.includes(event
|
322
|
+
.includes(cellData.value ?? event?.value);
|
323
|
+
|
275
324
|
if (!doesValueAlreadyExist) {
|
276
325
|
const newValueSpecification = (
|
277
326
|
isFilterBy ? postFilterEqualOperator : postFilterNotEqualOperator
|
278
327
|
).getDefaultFilterConditionValue(conditionState);
|
279
|
-
updateFilterConditionValue(
|
328
|
+
updateFilterConditionValue(
|
329
|
+
newValueSpecification as InstanceValue,
|
330
|
+
cellData,
|
331
|
+
);
|
280
332
|
instanceValue_setValues(
|
281
333
|
conditionState.value as InstanceValue,
|
282
334
|
[
|
@@ -289,32 +341,76 @@ const QueryBuilderGridResultContextMenu = observer(
|
|
289
341
|
}
|
290
342
|
};
|
291
343
|
|
292
|
-
const
|
344
|
+
const getFilterOperator = (
|
345
|
+
isFilterBy: boolean,
|
346
|
+
cellData: QueryBuilderTDSResultCellData,
|
347
|
+
): QueryBuilderPostFilterOperator => {
|
348
|
+
if (isFilterBy === true) {
|
349
|
+
if (cellData.value === null) {
|
350
|
+
return postFilterEmptyOperator;
|
351
|
+
} else {
|
352
|
+
return postFilterEqualOperator;
|
353
|
+
}
|
354
|
+
} else {
|
355
|
+
if (cellData.value === null) {
|
356
|
+
return postFilterNotEmptyOperator;
|
357
|
+
} else {
|
358
|
+
return postFilterNotEqualOperator;
|
359
|
+
}
|
360
|
+
}
|
361
|
+
};
|
362
|
+
|
363
|
+
const filterByOrOutValue = (
|
364
|
+
isFilterBy: boolean,
|
365
|
+
cellData: QueryBuilderTDSResultCellData,
|
366
|
+
): void => {
|
293
367
|
tdsState.setShowPostFilterPanel(true);
|
368
|
+
|
369
|
+
const operator = getFilterOperator(isFilterBy, cellData);
|
370
|
+
|
294
371
|
const existingPostFilterNode = getExistingPostFilterNode(
|
295
|
-
|
372
|
+
cellData.value === null
|
373
|
+
? [postFilterEmptyOperator, postFilterNotEmptyOperator]
|
374
|
+
: isFilterBy
|
296
375
|
? [postFilterEqualOperator, postFilterInOperator]
|
297
376
|
: [postFilterNotEqualOperator, postFilterNotInOperator],
|
377
|
+
cellData.columnName,
|
298
378
|
);
|
379
|
+
|
299
380
|
existingPostFilterNode === undefined
|
300
|
-
? generateNewPostFilterConditionNodeData(
|
301
|
-
|
302
|
-
)
|
381
|
+
? generateNewPostFilterConditionNodeData(operator, cellData).catch(
|
382
|
+
applicationStore.alertUnhandledError,
|
383
|
+
)
|
303
384
|
: updateExistingPostFilterConditionNodeData(
|
304
385
|
existingPostFilterNode,
|
305
386
|
isFilterBy,
|
387
|
+
cellData,
|
388
|
+
operator,
|
306
389
|
);
|
307
390
|
};
|
308
391
|
|
392
|
+
const filterByOrOutValues = (isFilterBy: boolean): void => {
|
393
|
+
tdsState.queryBuilderState.resultState.selectedCells.forEach(
|
394
|
+
(cellData) => {
|
395
|
+
filterByOrOutValue(isFilterBy, cellData);
|
396
|
+
},
|
397
|
+
);
|
398
|
+
};
|
399
|
+
|
309
400
|
const handleCopyCellValue = applicationStore.guardUnhandledError(() =>
|
310
401
|
applicationStore.clipboardService.copyTextToClipboard(
|
311
|
-
event
|
402
|
+
event?.value?.toString() ?? '',
|
312
403
|
),
|
313
404
|
);
|
314
405
|
|
315
406
|
const handleCopyRowValue = applicationStore.guardUnhandledError(() =>
|
316
407
|
applicationStore.clipboardService.copyTextToClipboard(
|
317
|
-
|
408
|
+
tdsState.queryBuilderState.resultState
|
409
|
+
.findRowFromRowIndex(
|
410
|
+
tdsState.queryBuilderState.resultState.selectedCells[0]?.coordinates
|
411
|
+
.rowIndex ?? 0,
|
412
|
+
)
|
413
|
+
.toString(),
|
318
414
|
),
|
319
415
|
);
|
320
416
|
|
@@ -323,7 +419,7 @@ const QueryBuilderGridResultContextMenu = observer(
|
|
323
419
|
<MenuContentItem
|
324
420
|
disabled={!projectionColumnState}
|
325
421
|
onClick={(): void => {
|
326
|
-
|
422
|
+
filterByOrOutValues(true);
|
327
423
|
}}
|
328
424
|
>
|
329
425
|
Filter By
|
@@ -331,7 +427,7 @@ const QueryBuilderGridResultContextMenu = observer(
|
|
331
427
|
<MenuContentItem
|
332
428
|
disabled={!projectionColumnState}
|
333
429
|
onClick={(): void => {
|
334
|
-
|
430
|
+
filterByOrOutValues(false);
|
335
431
|
}}
|
336
432
|
>
|
337
433
|
Filter Out
|
@@ -348,18 +444,201 @@ const QueryBuilderGridResultContextMenu = observer(
|
|
348
444
|
}),
|
349
445
|
);
|
350
446
|
|
447
|
+
type IQueryRendererParamsWithGridType = DataGridCellRendererParams & {
|
448
|
+
resultState: QueryBuilderResultState;
|
449
|
+
tdsExecutionResult: TDSExecutionResult;
|
450
|
+
};
|
451
|
+
|
452
|
+
const QueryResultCellRenderer = observer(
|
453
|
+
(params: IQueryRendererParamsWithGridType) => {
|
454
|
+
const resultState = params.resultState;
|
455
|
+
const tdsExecutionResult = params.tdsExecutionResult;
|
456
|
+
|
457
|
+
const cellValue = params.value as string;
|
458
|
+
const columnName = params.column?.getColId() ?? '';
|
459
|
+
|
460
|
+
const findCoordinatesFromResultValue = (
|
461
|
+
colId: string,
|
462
|
+
rowNumber: number,
|
463
|
+
): QueryBuilderTDSResultCellCoordinate => {
|
464
|
+
const colIndex = tdsExecutionResult.result.columns.findIndex(
|
465
|
+
(col) => col === colId,
|
466
|
+
);
|
467
|
+
|
468
|
+
return { rowIndex: rowNumber, colIndex: colIndex };
|
469
|
+
};
|
470
|
+
|
471
|
+
const currentCellCoordinates = findCoordinatesFromResultValue(
|
472
|
+
columnName,
|
473
|
+
params.rowIndex,
|
474
|
+
);
|
475
|
+
|
476
|
+
const cellInFilteredResults = resultState.selectedCells.some(
|
477
|
+
(result) =>
|
478
|
+
result.coordinates.colIndex === currentCellCoordinates.colIndex &&
|
479
|
+
result.coordinates.rowIndex === currentCellCoordinates.rowIndex,
|
480
|
+
);
|
481
|
+
|
482
|
+
const mouseDown: React.MouseEventHandler = (event) => {
|
483
|
+
event.preventDefault();
|
484
|
+
|
485
|
+
if (event.shiftKey) {
|
486
|
+
const coordinates = findCoordinatesFromResultValue(
|
487
|
+
columnName,
|
488
|
+
params.rowIndex,
|
489
|
+
);
|
490
|
+
const actualValue = resultState.findResultValueFromCoordinates([
|
491
|
+
coordinates.rowIndex,
|
492
|
+
coordinates.colIndex,
|
493
|
+
]);
|
494
|
+
resultState.addCellData({
|
495
|
+
value: actualValue,
|
496
|
+
columnName: columnName,
|
497
|
+
coordinates: coordinates,
|
498
|
+
});
|
499
|
+
return;
|
500
|
+
}
|
501
|
+
|
502
|
+
if (event.button === 0) {
|
503
|
+
resultState.setIsSelectingCells(true);
|
504
|
+
resultState.setSelectedCells([]);
|
505
|
+
const coordinates = findCoordinatesFromResultValue(
|
506
|
+
columnName,
|
507
|
+
params.rowIndex,
|
508
|
+
);
|
509
|
+
const actualValue = resultState.findResultValueFromCoordinates([
|
510
|
+
coordinates.rowIndex,
|
511
|
+
coordinates.colIndex,
|
512
|
+
]);
|
513
|
+
|
514
|
+
const rowNode = params.api.getRowNode(params.rowIndex.toString());
|
515
|
+
|
516
|
+
if (rowNode) {
|
517
|
+
params.api.refreshCells({
|
518
|
+
force: true,
|
519
|
+
columns: [columnName],
|
520
|
+
rowNodes: [rowNode],
|
521
|
+
});
|
522
|
+
}
|
523
|
+
resultState.setSelectedCells([
|
524
|
+
{
|
525
|
+
value: actualValue,
|
526
|
+
columnName: columnName,
|
527
|
+
coordinates: coordinates,
|
528
|
+
},
|
529
|
+
]);
|
530
|
+
}
|
531
|
+
};
|
532
|
+
const mouseUp: React.MouseEventHandler = (event) => {
|
533
|
+
resultState.setIsSelectingCells(false);
|
534
|
+
};
|
535
|
+
|
536
|
+
const mouseOver: React.MouseEventHandler = (event) => {
|
537
|
+
if (resultState.isSelectingCells) {
|
538
|
+
if (resultState.selectedCells.length < 1) {
|
539
|
+
return;
|
540
|
+
}
|
541
|
+
const results = resultState.selectedCells[0];
|
542
|
+
if (!results) {
|
543
|
+
return;
|
544
|
+
}
|
545
|
+
|
546
|
+
const firstCorner = results.coordinates;
|
547
|
+
const secondCorner = findCoordinatesFromResultValue(
|
548
|
+
columnName,
|
549
|
+
params.rowIndex,
|
550
|
+
);
|
551
|
+
|
552
|
+
resultState.setSelectedCells([results]);
|
553
|
+
|
554
|
+
const minRow = Math.min(firstCorner.rowIndex, secondCorner.rowIndex);
|
555
|
+
const minCol = Math.min(firstCorner.colIndex, secondCorner.colIndex);
|
556
|
+
const maxRow = Math.max(firstCorner.rowIndex, secondCorner.rowIndex);
|
557
|
+
const maxCol = Math.max(firstCorner.colIndex, secondCorner.colIndex);
|
558
|
+
|
559
|
+
for (let x = minRow; x <= maxRow; x++) {
|
560
|
+
for (let y = minCol; y <= maxCol; y++) {
|
561
|
+
const actualValue = resultState.findResultValueFromCoordinates([
|
562
|
+
x,
|
563
|
+
y,
|
564
|
+
]);
|
565
|
+
|
566
|
+
const valueAndColumnId = {
|
567
|
+
value: actualValue,
|
568
|
+
columnName: resultState.findColumnFromCoordinates(y),
|
569
|
+
coordinates: {
|
570
|
+
rowIndex: x,
|
571
|
+
colIndex: y,
|
572
|
+
},
|
573
|
+
} as QueryBuilderTDSResultCellData;
|
574
|
+
|
575
|
+
if (
|
576
|
+
!resultState.selectedCells.find(
|
577
|
+
(result) =>
|
578
|
+
result.coordinates.colIndex === y &&
|
579
|
+
result.coordinates.rowIndex === x,
|
580
|
+
)
|
581
|
+
) {
|
582
|
+
resultState.addCellData(valueAndColumnId);
|
583
|
+
}
|
584
|
+
}
|
585
|
+
}
|
586
|
+
}
|
587
|
+
|
588
|
+
resultState.setMouseOverCell(resultState.selectedCells[0] ?? null);
|
589
|
+
};
|
590
|
+
|
591
|
+
const fetchStructureImplementation =
|
592
|
+
resultState.queryBuilderState.fetchStructureState.implementation;
|
593
|
+
|
594
|
+
return (
|
595
|
+
<ContextMenu
|
596
|
+
content={
|
597
|
+
// NOTE: we only support this functionality for grid result with a projection fetch-structure
|
598
|
+
fetchStructureImplementation instanceof QueryBuilderTDSState ? (
|
599
|
+
<QueryBuilderGridResultContextMenu
|
600
|
+
event={resultState.mousedOverCell}
|
601
|
+
tdsState={fetchStructureImplementation}
|
602
|
+
/>
|
603
|
+
) : null
|
604
|
+
}
|
605
|
+
disabled={
|
606
|
+
!(
|
607
|
+
resultState.queryBuilderState.fetchStructureState
|
608
|
+
.implementation instanceof QueryBuilderTDSState
|
609
|
+
) ||
|
610
|
+
!resultState.queryBuilderState.isQuerySupported ||
|
611
|
+
!resultState.mousedOverCell
|
612
|
+
}
|
613
|
+
menuProps={{ elevation: 7 }}
|
614
|
+
key={params.value as string}
|
615
|
+
className={clsx('ag-theme-balham-dark query-builder__result__tds-grid')}
|
616
|
+
>
|
617
|
+
<div
|
618
|
+
className={clsx('query-builder__result__values__table__cell', {
|
619
|
+
'query-builder__result__values__table__cell--active':
|
620
|
+
cellInFilteredResults,
|
621
|
+
})}
|
622
|
+
onMouseDown={(event) => mouseDown(event)}
|
623
|
+
onMouseUp={(event) => mouseUp(event)}
|
624
|
+
onMouseOver={(event) => mouseOver(event)}
|
625
|
+
>
|
626
|
+
<span>{cellValue}</span>
|
627
|
+
</div>
|
628
|
+
</ContextMenu>
|
629
|
+
);
|
630
|
+
},
|
631
|
+
);
|
632
|
+
|
351
633
|
const QueryBuilderGridResult = observer(
|
352
634
|
(props: {
|
353
635
|
executionResult: TDSExecutionResult;
|
354
636
|
queryBuilderState: QueryBuilderState;
|
355
637
|
}) => {
|
356
638
|
const { executionResult, queryBuilderState } = props;
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
null,
|
361
|
-
);
|
362
|
-
const columns = executionResult.result.columns;
|
639
|
+
|
640
|
+
const resultState = queryBuilderState.resultState;
|
641
|
+
|
363
642
|
const rowData = executionResult.result.rows.map((_row, rowIdx) => {
|
364
643
|
const row: PlainObject = {};
|
365
644
|
const cols = executionResult.result.columns;
|
@@ -369,57 +648,42 @@ const QueryBuilderGridResult = observer(
|
|
369
648
|
// See https://github.com/finos/legend-studio/issues/1008
|
370
649
|
row[cols[colIdx] as string] = isBoolean(value) ? String(value) : value;
|
371
650
|
});
|
651
|
+
|
372
652
|
row.rowNumber = rowIdx;
|
373
653
|
return row;
|
374
654
|
});
|
375
655
|
|
376
656
|
return (
|
377
|
-
<
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
// options use the data belonging to the row that they are
|
408
|
-
// in. hence why we set the cell every time we mouse over
|
409
|
-
// rather than making user click multiple times.
|
410
|
-
onCellMouseOver={(event): void => {
|
411
|
-
cellDoubleClickedEvent.current = event;
|
412
|
-
}}
|
413
|
-
suppressFieldDotNotation={true}
|
414
|
-
columnDefs={columns.map((colName) => ({
|
415
|
-
minWidth: 50,
|
416
|
-
sortable: true,
|
417
|
-
resizable: true,
|
418
|
-
field: colName,
|
419
|
-
flex: 1,
|
420
|
-
}))}
|
421
|
-
/>
|
422
|
-
</ContextMenu>
|
657
|
+
<div className="query-builder__result__values__table">
|
658
|
+
<div
|
659
|
+
className={clsx(
|
660
|
+
'ag-theme-balham-dark query-builder__result__tds-grid',
|
661
|
+
)}
|
662
|
+
>
|
663
|
+
<DataGrid
|
664
|
+
rowData={rowData}
|
665
|
+
gridOptions={{
|
666
|
+
suppressScrollOnNewData: true,
|
667
|
+
getRowId: function (data) {
|
668
|
+
return data.data.rowNumber as string;
|
669
|
+
},
|
670
|
+
}}
|
671
|
+
suppressFieldDotNotation={true}
|
672
|
+
columnDefs={executionResult.result.columns.map((colName) => ({
|
673
|
+
minWidth: 50,
|
674
|
+
sortable: true,
|
675
|
+
resizable: true,
|
676
|
+
field: colName,
|
677
|
+
flex: 1,
|
678
|
+
cellRenderer: QueryResultCellRenderer,
|
679
|
+
cellRendererParams: {
|
680
|
+
resultState: resultState,
|
681
|
+
tdsExecutionResult: executionResult,
|
682
|
+
},
|
683
|
+
}))}
|
684
|
+
/>
|
685
|
+
</div>
|
686
|
+
</div>
|
423
687
|
);
|
424
688
|
},
|
425
689
|
);
|
@@ -531,6 +795,7 @@ export const QueryBuilderResultPanel = observer(
|
|
531
795
|
!queryBuilderState.isQuerySupported || isSupportedQueryValid;
|
532
796
|
|
533
797
|
const runQuery = (): void => {
|
798
|
+
resultState.setSelectedCells([]);
|
534
799
|
resultState.pressedRunQuery.inProgress();
|
535
800
|
if (queryParametersState.parameterStates.length) {
|
536
801
|
queryParametersState.parameterValuesEditorState.open(
|
@@ -564,6 +829,7 @@ export const QueryBuilderResultPanel = observer(
|
|
564
829
|
val === '' ? 0 : parseInt(val, 10),
|
565
830
|
);
|
566
831
|
};
|
832
|
+
|
567
833
|
const allowSettingPreviewLimit = queryBuilderState.isQuerySupported;
|
568
834
|
|
569
835
|
const copyExpression = (value: string): void => {
|