@finos/legend-query-builder 4.11.4 → 4.11.5
Sign up to get free protection for your applications and to get access to all the features.
- package/lib/components/QueryBuilder.js +1 -1
- package/lib/components/QueryBuilder.js.map +1 -1
- package/lib/components/execution-plan/SQLExecutionNodeViewer.js +1 -1
- package/lib/components/execution-plan/SQLExecutionNodeViewer.js.map +1 -1
- package/lib/components/{QueryBuilderResultPanel.d.ts → result/QueryBuilderResultPanel.d.ts} +1 -2
- package/lib/components/result/QueryBuilderResultPanel.d.ts.map +1 -0
- package/lib/components/result/QueryBuilderResultPanel.js +185 -0
- package/lib/components/result/QueryBuilderResultPanel.js.map +1 -0
- package/lib/components/result/tds/QueryBuilderTDSGridResult.d.ts +24 -0
- package/lib/components/result/tds/QueryBuilderTDSGridResult.d.ts.map +1 -0
- package/lib/components/result/tds/QueryBuilderTDSGridResult.js +140 -0
- package/lib/components/result/tds/QueryBuilderTDSGridResult.js.map +1 -0
- package/lib/components/result/tds/QueryBuilderTDSResultShared.d.ts +41 -0
- package/lib/components/result/tds/QueryBuilderTDSResultShared.d.ts.map +1 -0
- package/lib/components/result/tds/QueryBuilderTDSResultShared.js +465 -0
- package/lib/components/result/tds/QueryBuilderTDSResultShared.js.map +1 -0
- package/lib/components/result/tds/QueryBuilderTDSSimpleGridResult.d.ts +24 -0
- package/lib/components/result/tds/QueryBuilderTDSSimpleGridResult.d.ts.map +1 -0
- package/lib/components/result/tds/QueryBuilderTDSSimpleGridResult.js +47 -0
- package/lib/components/result/tds/QueryBuilderTDSSimpleGridResult.js.map +1 -0
- 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 +5 -1
- package/lib/stores/QueryBuilderResultState.d.ts.map +1 -1
- package/lib/stores/QueryBuilderResultState.js.map +1 -1
- package/package.json +2 -2
- package/src/components/QueryBuilder.tsx +1 -1
- package/src/components/execution-plan/SQLExecutionNodeViewer.tsx +1 -1
- package/src/components/result/QueryBuilderResultPanel.tsx +570 -0
- package/src/components/result/tds/QueryBuilderTDSGridResult.tsx +239 -0
- package/src/components/result/tds/QueryBuilderTDSResultShared.tsx +866 -0
- package/src/components/result/tds/QueryBuilderTDSSimpleGridResult.tsx +80 -0
- package/src/stores/QueryBuilderResultState.ts +12 -1
- package/tsconfig.json +4 -1
- package/lib/components/QueryBuilderResultPanel.d.ts.map +0 -1
- package/lib/components/QueryBuilderResultPanel.js +0 -633
- package/lib/components/QueryBuilderResultPanel.js.map +0 -1
- package/src/components/QueryBuilderResultPanel.tsx +0 -1412
@@ -1,633 +0,0 @@
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
2
|
-
/**
|
3
|
-
* Copyright (c) 2020-present, Goldman Sachs
|
4
|
-
*
|
5
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
-
* you may not use this file except in compliance with the License.
|
7
|
-
* You may obtain a copy of the License at
|
8
|
-
*
|
9
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
10
|
-
*
|
11
|
-
* Unless required by applicable law or agreed to in writing, software
|
12
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
-
* See the License for the specific language governing permissions and
|
15
|
-
* limitations under the License.
|
16
|
-
*/
|
17
|
-
import { BlankPanelContent, PanelLoadingIndicator, PlayIcon, DropdownMenu, MenuContent, MenuContentItem, CaretDownIcon, ContextMenu, clsx, PauseCircleIcon, ExclamationTriangleIcon, PanelContent, MenuContentDivider, Button, SQLIcon, Dialog, Modal, ModalBody, ModalFooter, ModalFooterButton, ModalHeader, PanelDivider, SquareIcon, CheckSquareIcon, } from '@finos/legend-art';
|
18
|
-
import { format as formatSQL } from 'sql-formatter';
|
19
|
-
import { observer } from 'mobx-react-lite';
|
20
|
-
import { flowResult } from 'mobx';
|
21
|
-
import { InstanceValue, extractExecutionResultValues, TDSExecutionResult, RawExecutionResult, EnumValueInstanceValue, EnumValueExplicitReference, RelationalExecutionActivities, getTDSRowRankByColumnInAsc, PRIMITIVE_TYPE, } from '@finos/legend-graph';
|
22
|
-
import { ActionAlertActionType, ActionAlertType, DEFAULT_TAB_SIZE, useApplicationStore, } from '@finos/legend-application';
|
23
|
-
import { assertErrorThrown, guaranteeNonNullable, isBoolean, prettyDuration, filterByType, isValidURL, isString, isNumber, } from '@finos/legend-shared';
|
24
|
-
import { forwardRef, useRef, useState } from 'react';
|
25
|
-
import { QueryBuilderDerivationProjectionColumnState, QueryBuilderProjectionColumnState, } from '../stores/fetch-structure/tds/projection/QueryBuilderProjectionColumnState.js';
|
26
|
-
import { PostFilterConditionState, QueryBuilderPostFilterTreeConditionNodeData, PostFilterValueSpecConditionValueState, } from '../stores/fetch-structure/tds/post-filter/QueryBuilderPostFilterState.js';
|
27
|
-
import { QueryBuilderPostFilterOperator_Equal, QueryBuilderPostFilterOperator_NotEqual, } from '../stores/fetch-structure/tds/post-filter/operators/QueryBuilderPostFilterOperator_Equal.js';
|
28
|
-
import { QueryBuilderPostFilterOperator_In, QueryBuilderPostFilterOperator_NotIn, } from '../stores/fetch-structure/tds/post-filter/operators/QueryBuilderPostFilterOperator_In.js';
|
29
|
-
import { QueryBuilderTDSState } from '../stores/fetch-structure/tds/QueryBuilderTDSState.js';
|
30
|
-
import { instanceValue_setValue, instanceValue_setValues, } from '../stores/shared/ValueSpecificationModifierHelper.js';
|
31
|
-
import { PARAMETER_SUBMIT_ACTION } from '../stores/shared/LambdaParameterState.js';
|
32
|
-
import { QUERY_BUILDER_TEST_ID } from '../__lib__/QueryBuilderTesting.js';
|
33
|
-
import { DataGrid, } from '@finos/legend-lego/data-grid';
|
34
|
-
import { CODE_EDITOR_LANGUAGE, CodeEditor, } from '@finos/legend-lego/code-editor';
|
35
|
-
import { ExecutionPlanViewer } from './execution-plan/ExecutionPlanViewer.js';
|
36
|
-
import { QueryBuilderPostFilterOperator_IsEmpty, QueryBuilderPostFilterOperator_IsNotEmpty, } from '../stores/fetch-structure/tds/post-filter/operators/QueryBuilderPostFilterOperator_IsEmpty.js';
|
37
|
-
import { QueryUsageViewer } from './QueryUsageViewer.js';
|
38
|
-
import { DEFAULT_LOCALE } from '../graph-manager/QueryBuilderConst.js';
|
39
|
-
import { DocumentationLink } from '@finos/legend-lego/application';
|
40
|
-
import { QUERY_BUILDER_DOCUMENTATION_KEY } from '../__lib__/QueryBuilderDocumentation.js';
|
41
|
-
export const tryToFormatSql = (sql) => {
|
42
|
-
try {
|
43
|
-
const formattedSql = formatSQL(sql, { language: 'mysql' });
|
44
|
-
return formattedSql;
|
45
|
-
}
|
46
|
-
catch {
|
47
|
-
try {
|
48
|
-
const formattedSql = formatSQL(sql);
|
49
|
-
return formattedSql;
|
50
|
-
}
|
51
|
-
catch {
|
52
|
-
return sql;
|
53
|
-
}
|
54
|
-
}
|
55
|
-
};
|
56
|
-
const QueryBuilderGridResultContextMenu = observer(forwardRef(function QueryBuilderResultContextMenu(props, ref) {
|
57
|
-
const { data, tdsState } = props;
|
58
|
-
const applicationStore = useApplicationStore();
|
59
|
-
const postFilterEqualOperator = new QueryBuilderPostFilterOperator_Equal();
|
60
|
-
const postFilterInOperator = new QueryBuilderPostFilterOperator_In();
|
61
|
-
const postFilterEmptyOperator = new QueryBuilderPostFilterOperator_IsEmpty();
|
62
|
-
const postFilterNotEmptyOperator = new QueryBuilderPostFilterOperator_IsNotEmpty();
|
63
|
-
const postFilterNotEqualOperator = new QueryBuilderPostFilterOperator_NotEqual();
|
64
|
-
const postFilterNotInOperator = new QueryBuilderPostFilterOperator_NotIn();
|
65
|
-
const postFilterState = tdsState.postFilterState;
|
66
|
-
const projectionColumnState = tdsState.projectionColumns
|
67
|
-
.filter((c) => c.columnName === data?.columnName)
|
68
|
-
.concat(tdsState.aggregationState.columns
|
69
|
-
.filter((c) => c.columnName === data?.columnName)
|
70
|
-
.map((ag) => ag.projectionColumnState))[0];
|
71
|
-
const getExistingPostFilterNode = (operators, projectionColumnName) => Array.from(postFilterState.nodes.values())
|
72
|
-
.filter((v) => v instanceof QueryBuilderPostFilterTreeConditionNodeData &&
|
73
|
-
v.condition.leftConditionValue instanceof
|
74
|
-
QueryBuilderProjectionColumnState)
|
75
|
-
.filter((n) => n.condition
|
76
|
-
.leftConditionValue.columnName ===
|
77
|
-
(projectionColumnName ?? projectionColumnState?.columnName) &&
|
78
|
-
operators
|
79
|
-
.map((op) => op.getLabel())
|
80
|
-
.includes(n.condition.operator.getLabel()))[0];
|
81
|
-
const updateFilterConditionValue = (conditionValue, cellData) => {
|
82
|
-
if (cellData.value) {
|
83
|
-
instanceValue_setValue(conditionValue, conditionValue instanceof EnumValueInstanceValue
|
84
|
-
? EnumValueExplicitReference.create(guaranteeNonNullable((conditionValue.genericType?.ownerReference
|
85
|
-
.value).values.filter((v) => v.name === cellData.value)[0]))
|
86
|
-
: cellData.value, 0, tdsState.queryBuilderState.observerContext);
|
87
|
-
}
|
88
|
-
};
|
89
|
-
const generateNewPostFilterConditionNodeData = async (operator, cellData) => {
|
90
|
-
let postFilterConditionState;
|
91
|
-
try {
|
92
|
-
const possibleProjectionColumnState = cellData.columnName
|
93
|
-
? tdsState.projectionColumns
|
94
|
-
.filter((c) => c.columnName === cellData.columnName)
|
95
|
-
.concat(tdsState.aggregationState.columns
|
96
|
-
.filter((c) => c.columnName === cellData.columnName)
|
97
|
-
.map((ag) => ag.projectionColumnState))[0]
|
98
|
-
: projectionColumnState;
|
99
|
-
if (possibleProjectionColumnState) {
|
100
|
-
postFilterConditionState = new PostFilterConditionState(postFilterState, possibleProjectionColumnState, operator);
|
101
|
-
if (projectionColumnState instanceof
|
102
|
-
QueryBuilderDerivationProjectionColumnState) {
|
103
|
-
await flowResult(projectionColumnState.fetchDerivationLambdaReturnType());
|
104
|
-
}
|
105
|
-
const defaultFilterConditionValue = postFilterConditionState.operator.getDefaultFilterConditionValue(postFilterConditionState);
|
106
|
-
postFilterConditionState.buildFromValueSpec(defaultFilterConditionValue);
|
107
|
-
updateFilterConditionValue(defaultFilterConditionValue, cellData);
|
108
|
-
postFilterState.addNodeFromNode(new QueryBuilderPostFilterTreeConditionNodeData(undefined, postFilterConditionState), undefined);
|
109
|
-
}
|
110
|
-
}
|
111
|
-
catch (error) {
|
112
|
-
assertErrorThrown(error);
|
113
|
-
applicationStore.notificationService.notifyWarning(error.message);
|
114
|
-
return;
|
115
|
-
}
|
116
|
-
};
|
117
|
-
const updateExistingPostFilterConditionNodeData = (existingPostFilterNode, isFilterBy, cellData, operator) => {
|
118
|
-
if (operator === postFilterEmptyOperator ||
|
119
|
-
operator === postFilterNotEmptyOperator) {
|
120
|
-
const conditionState = existingPostFilterNode.condition;
|
121
|
-
if (conditionState.operator.getLabel() !== operator.getLabel()) {
|
122
|
-
conditionState.changeOperator(isFilterBy ? postFilterEmptyOperator : postFilterNotEmptyOperator);
|
123
|
-
}
|
124
|
-
return;
|
125
|
-
}
|
126
|
-
const conditionState = existingPostFilterNode.condition;
|
127
|
-
const rightSide = conditionState.rightConditionValue;
|
128
|
-
if (rightSide instanceof PostFilterValueSpecConditionValueState) {
|
129
|
-
if (conditionState.operator.getLabel() === operator.getLabel()) {
|
130
|
-
const doesValueAlreadyExist = rightSide.value instanceof InstanceValue &&
|
131
|
-
(rightSide.value instanceof EnumValueInstanceValue
|
132
|
-
? rightSide.value.values.map((ef) => ef.value.name)
|
133
|
-
: rightSide.value.values).includes(cellData.value);
|
134
|
-
if (!doesValueAlreadyExist) {
|
135
|
-
const currentValueSpecificaton = rightSide.value;
|
136
|
-
const newValueSpecification = conditionState.operator.getDefaultFilterConditionValue(conditionState);
|
137
|
-
updateFilterConditionValue(newValueSpecification, cellData);
|
138
|
-
conditionState.changeOperator(isFilterBy ? postFilterInOperator : postFilterNotInOperator);
|
139
|
-
instanceValue_setValues(rightSide.value, [currentValueSpecificaton, newValueSpecification], tdsState.queryBuilderState.observerContext);
|
140
|
-
}
|
141
|
-
}
|
142
|
-
else {
|
143
|
-
const doesValueAlreadyExist = rightSide.value instanceof InstanceValue &&
|
144
|
-
rightSide.value.values
|
145
|
-
.filter((v) => v instanceof InstanceValue)
|
146
|
-
.map((v) => v instanceof EnumValueInstanceValue
|
147
|
-
? v.values.map((ef) => ef.value.name)
|
148
|
-
: v.values)
|
149
|
-
.flat()
|
150
|
-
.includes(cellData.value ?? data?.value);
|
151
|
-
if (!doesValueAlreadyExist) {
|
152
|
-
const newValueSpecification = (isFilterBy ? postFilterEqualOperator : postFilterNotEqualOperator).getDefaultFilterConditionValue(conditionState);
|
153
|
-
updateFilterConditionValue(newValueSpecification, cellData);
|
154
|
-
instanceValue_setValues(rightSide.value, [
|
155
|
-
...rightSide.value.values,
|
156
|
-
newValueSpecification,
|
157
|
-
], tdsState.queryBuilderState.observerContext);
|
158
|
-
}
|
159
|
-
}
|
160
|
-
}
|
161
|
-
};
|
162
|
-
const getFilterOperator = (isFilterBy, cellData) => {
|
163
|
-
if (isFilterBy === true) {
|
164
|
-
if (cellData.value === null) {
|
165
|
-
return postFilterEmptyOperator;
|
166
|
-
}
|
167
|
-
else {
|
168
|
-
return postFilterEqualOperator;
|
169
|
-
}
|
170
|
-
}
|
171
|
-
else {
|
172
|
-
if (cellData.value === null) {
|
173
|
-
return postFilterNotEmptyOperator;
|
174
|
-
}
|
175
|
-
else {
|
176
|
-
return postFilterNotEqualOperator;
|
177
|
-
}
|
178
|
-
}
|
179
|
-
};
|
180
|
-
const filterByOrOutValue = (isFilterBy, cellData) => {
|
181
|
-
tdsState.setShowPostFilterPanel(true);
|
182
|
-
const operator = getFilterOperator(isFilterBy, cellData);
|
183
|
-
const existingPostFilterNode = getExistingPostFilterNode(cellData.value === null
|
184
|
-
? [postFilterEmptyOperator, postFilterNotEmptyOperator]
|
185
|
-
: isFilterBy
|
186
|
-
? [postFilterEqualOperator, postFilterInOperator]
|
187
|
-
: [postFilterNotEqualOperator, postFilterNotInOperator], cellData.columnName);
|
188
|
-
existingPostFilterNode === undefined
|
189
|
-
? generateNewPostFilterConditionNodeData(operator, cellData).catch(applicationStore.alertUnhandledError)
|
190
|
-
: updateExistingPostFilterConditionNodeData(existingPostFilterNode, isFilterBy, cellData, operator);
|
191
|
-
};
|
192
|
-
const filterByOrOutValues = (isFilterBy) => {
|
193
|
-
tdsState.queryBuilderState.resultState.selectedCells.forEach((cellData) => {
|
194
|
-
filterByOrOutValue(isFilterBy, cellData);
|
195
|
-
});
|
196
|
-
};
|
197
|
-
const handleCopyCellValue = applicationStore.guardUnhandledError(() => applicationStore.clipboardService.copyTextToClipboard(data?.value?.toString() ?? ''));
|
198
|
-
const findRowFromRowIndex = (rowIndex) => {
|
199
|
-
if (!tdsState.queryBuilderState.resultState.executionResult ||
|
200
|
-
!(tdsState.queryBuilderState.resultState.executionResult instanceof
|
201
|
-
TDSExecutionResult)) {
|
202
|
-
return [''];
|
203
|
-
}
|
204
|
-
return (tdsState.queryBuilderState.resultState.executionResult.result.rows[rowIndex]?.values ?? ['']);
|
205
|
-
};
|
206
|
-
const handleCopyRowValue = applicationStore.guardUnhandledError(() => applicationStore.clipboardService.copyTextToClipboard(findRowFromRowIndex(tdsState.queryBuilderState.resultState.selectedCells[0]?.coordinates
|
207
|
-
.rowIndex ?? 0).toString()));
|
208
|
-
return (_jsxs(MenuContent, { ref: ref, children: [_jsx(MenuContentItem, { disabled: !projectionColumnState, onClick: () => {
|
209
|
-
filterByOrOutValues(true);
|
210
|
-
}, children: "Filter By" }), _jsx(MenuContentItem, { disabled: !projectionColumnState, onClick: () => {
|
211
|
-
filterByOrOutValues(false);
|
212
|
-
}, children: "Filter Out" }), _jsx(MenuContentDivider, {}), _jsx(MenuContentItem, { onClick: handleCopyCellValue, children: "Copy Cell Value" }), _jsx(MenuContentItem, { onClick: handleCopyRowValue, children: "Copy Row Value" })] }));
|
213
|
-
}));
|
214
|
-
const QueryResultCellRenderer = observer((params) => {
|
215
|
-
const resultState = params.resultState;
|
216
|
-
const tdsExecutionResult = params.tdsExecutionResult;
|
217
|
-
const fetchStructureImplementation = resultState.queryBuilderState.fetchStructureState.implementation;
|
218
|
-
const cellValue = params.value;
|
219
|
-
const formattedCellValue = () => {
|
220
|
-
if (isNumber(cellValue)) {
|
221
|
-
return Intl.NumberFormat(DEFAULT_LOCALE, {
|
222
|
-
maximumFractionDigits: 4,
|
223
|
-
}).format(Number(cellValue));
|
224
|
-
}
|
225
|
-
return cellValue;
|
226
|
-
};
|
227
|
-
const cellValueUrlLink = isString(cellValue) && isValidURL(cellValue) ? cellValue : undefined;
|
228
|
-
const columnName = params.column?.getColId() ?? '';
|
229
|
-
const findCoordinatesFromResultValue = (colId, rowNumber) => {
|
230
|
-
const colIndex = tdsExecutionResult.result.columns.findIndex((col) => col === colId);
|
231
|
-
return { rowIndex: rowNumber, colIndex: colIndex };
|
232
|
-
};
|
233
|
-
const currentCellCoordinates = findCoordinatesFromResultValue(columnName, params.rowIndex);
|
234
|
-
const cellInFilteredResults = resultState.selectedCells.some((result) => result.coordinates.colIndex === currentCellCoordinates.colIndex &&
|
235
|
-
result.coordinates.rowIndex === currentCellCoordinates.rowIndex);
|
236
|
-
const findColumnFromCoordinates = (colIndex) => {
|
237
|
-
if (!resultState.executionResult ||
|
238
|
-
!(resultState.executionResult instanceof TDSExecutionResult)) {
|
239
|
-
return undefined;
|
240
|
-
}
|
241
|
-
return resultState.executionResult.result.columns[colIndex];
|
242
|
-
};
|
243
|
-
const findResultValueFromCoordinates = (resultCoordinate) => {
|
244
|
-
const rowIndex = resultCoordinate[0];
|
245
|
-
const colIndex = resultCoordinate[1];
|
246
|
-
if (!resultState.executionResult ||
|
247
|
-
!(resultState.executionResult instanceof TDSExecutionResult)) {
|
248
|
-
return undefined;
|
249
|
-
}
|
250
|
-
if (params.columnApi.getColumnState()[colIndex]?.sort === 'asc') {
|
251
|
-
resultState.executionResult.result.rows.sort((a, b) => getTDSRowRankByColumnInAsc(a, b, colIndex));
|
252
|
-
}
|
253
|
-
else if (params.columnApi.getColumnState()[colIndex]?.sort === 'desc') {
|
254
|
-
resultState.executionResult.result.rows.sort((a, b) => getTDSRowRankByColumnInAsc(b, a, colIndex));
|
255
|
-
}
|
256
|
-
return resultState.executionResult.result.rows[rowIndex]?.values[colIndex];
|
257
|
-
};
|
258
|
-
const isCoordinatesSelected = (resultCoordinate) => resultState.selectedCells.some((cell) => cell.coordinates.rowIndex === resultCoordinate.rowIndex &&
|
259
|
-
cell.coordinates.colIndex === resultCoordinate.colIndex);
|
260
|
-
const mouseDown = (event) => {
|
261
|
-
event.preventDefault();
|
262
|
-
if (event.shiftKey) {
|
263
|
-
const coordinates = findCoordinatesFromResultValue(columnName, params.rowIndex);
|
264
|
-
const actualValue = findResultValueFromCoordinates([
|
265
|
-
coordinates.rowIndex,
|
266
|
-
coordinates.colIndex,
|
267
|
-
]);
|
268
|
-
resultState.addSelectedCell({
|
269
|
-
value: actualValue,
|
270
|
-
columnName: columnName,
|
271
|
-
coordinates: coordinates,
|
272
|
-
});
|
273
|
-
return;
|
274
|
-
}
|
275
|
-
if (event.button === 0) {
|
276
|
-
resultState.setIsSelectingCells(true);
|
277
|
-
resultState.setSelectedCells([]);
|
278
|
-
const coordinates = findCoordinatesFromResultValue(columnName, params.rowIndex);
|
279
|
-
const actualValue = findResultValueFromCoordinates([
|
280
|
-
coordinates.rowIndex,
|
281
|
-
coordinates.colIndex,
|
282
|
-
]);
|
283
|
-
resultState.setSelectedCells([
|
284
|
-
{
|
285
|
-
value: actualValue,
|
286
|
-
columnName: columnName,
|
287
|
-
coordinates: coordinates,
|
288
|
-
},
|
289
|
-
]);
|
290
|
-
resultState.setMouseOverCell(resultState.selectedCells[0] ?? null);
|
291
|
-
}
|
292
|
-
if (event.button === 2) {
|
293
|
-
const coordinates = findCoordinatesFromResultValue(columnName, params.rowIndex);
|
294
|
-
const isInSelected = isCoordinatesSelected(coordinates);
|
295
|
-
if (!isInSelected) {
|
296
|
-
const actualValue = findResultValueFromCoordinates([
|
297
|
-
coordinates.rowIndex,
|
298
|
-
coordinates.colIndex,
|
299
|
-
]);
|
300
|
-
resultState.setSelectedCells([
|
301
|
-
{
|
302
|
-
value: actualValue,
|
303
|
-
columnName: columnName,
|
304
|
-
coordinates: coordinates,
|
305
|
-
},
|
306
|
-
]);
|
307
|
-
resultState.setMouseOverCell(resultState.selectedCells[0] ?? null);
|
308
|
-
}
|
309
|
-
}
|
310
|
-
};
|
311
|
-
const mouseUp = (event) => {
|
312
|
-
resultState.setIsSelectingCells(false);
|
313
|
-
};
|
314
|
-
const mouseOver = (event) => {
|
315
|
-
if (resultState.isSelectingCells) {
|
316
|
-
if (resultState.selectedCells.length < 1) {
|
317
|
-
return;
|
318
|
-
}
|
319
|
-
const results = resultState.selectedCells[0];
|
320
|
-
if (!results) {
|
321
|
-
return;
|
322
|
-
}
|
323
|
-
const firstCorner = results.coordinates;
|
324
|
-
const secondCorner = findCoordinatesFromResultValue(columnName, params.rowIndex);
|
325
|
-
resultState.setSelectedCells([results]);
|
326
|
-
const minRow = Math.min(firstCorner.rowIndex, secondCorner.rowIndex);
|
327
|
-
const minCol = Math.min(firstCorner.colIndex, secondCorner.colIndex);
|
328
|
-
const maxRow = Math.max(firstCorner.rowIndex, secondCorner.rowIndex);
|
329
|
-
const maxCol = Math.max(firstCorner.colIndex, secondCorner.colIndex);
|
330
|
-
for (let x = minRow; x <= maxRow; x++) {
|
331
|
-
for (let y = minCol; y <= maxCol; y++) {
|
332
|
-
const actualValue = findResultValueFromCoordinates([x, y]);
|
333
|
-
const valueAndColumnId = {
|
334
|
-
value: actualValue,
|
335
|
-
columnName: findColumnFromCoordinates(y),
|
336
|
-
coordinates: {
|
337
|
-
rowIndex: x,
|
338
|
-
colIndex: y,
|
339
|
-
},
|
340
|
-
};
|
341
|
-
if (!resultState.selectedCells.find((result) => result.coordinates.colIndex === y &&
|
342
|
-
result.coordinates.rowIndex === x)) {
|
343
|
-
resultState.addSelectedCell(valueAndColumnId);
|
344
|
-
}
|
345
|
-
}
|
346
|
-
}
|
347
|
-
}
|
348
|
-
resultState.setMouseOverCell(resultState.selectedCells[0] ?? null);
|
349
|
-
};
|
350
|
-
return (_jsx(ContextMenu, { content:
|
351
|
-
// NOTE: we only support this functionality for grid result with a projection fetch-structure
|
352
|
-
fetchStructureImplementation instanceof QueryBuilderTDSState ? (_jsx(QueryBuilderGridResultContextMenu, { data: resultState.mousedOverCell, tdsState: fetchStructureImplementation })) : null, disabled: !(resultState.queryBuilderState.fetchStructureState
|
353
|
-
.implementation instanceof QueryBuilderTDSState) ||
|
354
|
-
!resultState.queryBuilderState.isQuerySupported ||
|
355
|
-
!resultState.mousedOverCell, menuProps: { elevation: 7 }, className: clsx('ag-theme-balham-dark query-builder__result__tds-grid'), children: _jsx("div", { className: clsx('query-builder__result__values__table__cell', {
|
356
|
-
'query-builder__result__values__table__cell--active': cellInFilteredResults,
|
357
|
-
}), onMouseDown: (event) => mouseDown(event), onMouseUp: (event) => mouseUp(event), onMouseOver: (event) => mouseOver(event), children: cellValueUrlLink ? (_jsx("a", { href: cellValueUrlLink, target: "_blank", rel: "noreferrer", children: cellValueUrlLink })) : (_jsx("span", { children: formattedCellValue() })) }) }));
|
358
|
-
});
|
359
|
-
const getColumnCustomizations = (result, columnName) => {
|
360
|
-
const columnType = result.builder.columns.find((col) => col.name === columnName)?.type;
|
361
|
-
switch (columnType) {
|
362
|
-
case PRIMITIVE_TYPE.STRING:
|
363
|
-
return {
|
364
|
-
filter: 'agTextColumnFilter',
|
365
|
-
allowedAggFuncs: ['count'],
|
366
|
-
};
|
367
|
-
case PRIMITIVE_TYPE.DATE:
|
368
|
-
case PRIMITIVE_TYPE.DATETIME:
|
369
|
-
case PRIMITIVE_TYPE.STRICTDATE:
|
370
|
-
return {
|
371
|
-
filter: 'agDateColumnFilter',
|
372
|
-
allowedAggFuncs: ['count'],
|
373
|
-
};
|
374
|
-
case PRIMITIVE_TYPE.DECIMAL:
|
375
|
-
case PRIMITIVE_TYPE.INTEGER:
|
376
|
-
case PRIMITIVE_TYPE.FLOAT:
|
377
|
-
return {
|
378
|
-
filter: 'agNumberColumnFilter',
|
379
|
-
allowedAggFuncs: ['count', 'sum', 'max', 'min', 'avg'],
|
380
|
-
};
|
381
|
-
default:
|
382
|
-
return {
|
383
|
-
allowedAggFuncs: ['count'],
|
384
|
-
};
|
385
|
-
}
|
386
|
-
};
|
387
|
-
const QueryBuilderGridResult = observer((props) => {
|
388
|
-
const { executionResult, queryBuilderState } = props;
|
389
|
-
const [columnAPi, setColumnApi] = useState(undefined);
|
390
|
-
const resultState = queryBuilderState.resultState;
|
391
|
-
const isAdvancedModeEnabled = queryBuilderState.isAdvancedModeEnabled;
|
392
|
-
const colDefs = isAdvancedModeEnabled
|
393
|
-
? executionResult.result.columns.map((colName) => {
|
394
|
-
const col = {
|
395
|
-
minWidth: 50,
|
396
|
-
sortable: true,
|
397
|
-
resizable: true,
|
398
|
-
field: colName,
|
399
|
-
flex: 1,
|
400
|
-
enablePivot: true,
|
401
|
-
enableRowGroup: true,
|
402
|
-
enableValue: true,
|
403
|
-
...getColumnCustomizations(executionResult, colName),
|
404
|
-
};
|
405
|
-
const persistedColumn = resultState.gridConfig.columns.find((c) => c.colId === colName);
|
406
|
-
if (persistedColumn) {
|
407
|
-
if (persistedColumn.width) {
|
408
|
-
col.width = persistedColumn.width;
|
409
|
-
}
|
410
|
-
col.pinned = persistedColumn.pinned ?? null;
|
411
|
-
col.rowGroup = persistedColumn.rowGroup ?? false;
|
412
|
-
col.rowGroupIndex = persistedColumn.rowGroupIndex ?? null;
|
413
|
-
col.aggFunc = persistedColumn.aggFunc ?? null;
|
414
|
-
col.pivot = persistedColumn.pivot ?? false;
|
415
|
-
col.hide = persistedColumn.hide ?? false;
|
416
|
-
}
|
417
|
-
return col;
|
418
|
-
})
|
419
|
-
: executionResult.result.columns.map((colName) => ({
|
420
|
-
minWidth: 50,
|
421
|
-
sortable: true,
|
422
|
-
resizable: true,
|
423
|
-
field: colName,
|
424
|
-
flex: 1,
|
425
|
-
cellRenderer: QueryResultCellRenderer,
|
426
|
-
cellRendererParams: {
|
427
|
-
resultState: resultState,
|
428
|
-
tdsExecutionResult: executionResult,
|
429
|
-
},
|
430
|
-
}));
|
431
|
-
const sideBar = isAdvancedModeEnabled ? ['columns', 'filters'] : null;
|
432
|
-
const rowData = executionResult.result.rows.map((_row, rowIdx) => {
|
433
|
-
const row = {};
|
434
|
-
const cols = executionResult.result.columns;
|
435
|
-
_row.values.forEach((value, colIdx) => {
|
436
|
-
// `ag-grid` shows `false` value as empty string so we have
|
437
|
-
// call `.toString()` to avoid this behavior.
|
438
|
-
// See https://github.com/finos/legend-studio/issues/1008
|
439
|
-
row[cols[colIdx]] = isBoolean(value) ? String(value) : value;
|
440
|
-
});
|
441
|
-
row.rowNumber = rowIdx;
|
442
|
-
return row;
|
443
|
-
});
|
444
|
-
const onSaveGridColumnState = () => {
|
445
|
-
if (!columnAPi) {
|
446
|
-
return;
|
447
|
-
}
|
448
|
-
resultState.setGridConfig({
|
449
|
-
columns: columnAPi.getColumnState(),
|
450
|
-
isPivotModeEnabled: columnAPi.isPivotMode(),
|
451
|
-
});
|
452
|
-
};
|
453
|
-
return (_jsx("div", { className: "query-builder__result__values__table", children: _jsx("div", { className: clsx('ag-theme-balham-dark query-builder__result__tds-grid'), children: isAdvancedModeEnabled ? (_jsx(DataGrid, { rowData: rowData, onGridReady: (params) => {
|
454
|
-
setColumnApi(params.columnApi);
|
455
|
-
params.columnApi.setPivotMode(resultState.gridConfig.isPivotModeEnabled);
|
456
|
-
}, gridOptions: {
|
457
|
-
suppressScrollOnNewData: true,
|
458
|
-
getRowId: (data) => data.data.rowNumber,
|
459
|
-
rowSelection: 'multiple',
|
460
|
-
pivotPanelShow: 'always',
|
461
|
-
rowGroupPanelShow: 'always',
|
462
|
-
},
|
463
|
-
// NOTE: when column definition changed, we need to force refresh the cell to make sure the cell renderer is updated
|
464
|
-
// See https://stackoverflow.com/questions/56341073/how-to-refresh-an-ag-grid-when-a-change-occurs-inside-a-custom-cell-renderer-com
|
465
|
-
onRowDataUpdated: (params) => {
|
466
|
-
params.api.refreshCells({ force: true });
|
467
|
-
}, suppressFieldDotNotation: true, suppressContextMenu: !isAdvancedModeEnabled, columnDefs: colDefs, sideBar: sideBar, onColumnVisible: onSaveGridColumnState, onColumnPinned: onSaveGridColumnState, onColumnResized: onSaveGridColumnState, onColumnRowGroupChanged: onSaveGridColumnState, onColumnValueChanged: onSaveGridColumnState, onColumnPivotChanged: onSaveGridColumnState, onColumnPivotModeChanged: onSaveGridColumnState })) : (_jsx(DataGrid, { rowData: rowData, gridOptions: {
|
468
|
-
suppressScrollOnNewData: true,
|
469
|
-
getRowId: (data) => data.data.rowNumber,
|
470
|
-
rowSelection: 'multiple',
|
471
|
-
},
|
472
|
-
// NOTE: when column definition changed, we need to force refresh the cell to make sure the cell renderer is updated
|
473
|
-
// See https://stackoverflow.com/questions/56341073/how-to-refresh-an-ag-grid-when-a-change-occurs-inside-a-custom-cell-renderer-com
|
474
|
-
onRowDataUpdated: (params) => {
|
475
|
-
params.api.refreshCells({ force: true });
|
476
|
-
}, suppressFieldDotNotation: true, suppressContextMenu: !isAdvancedModeEnabled, columnDefs: colDefs })) }) }));
|
477
|
-
});
|
478
|
-
const QueryBuilderResultValues = observer((props) => {
|
479
|
-
const { executionResult, queryBuilderState } = props;
|
480
|
-
if (executionResult instanceof TDSExecutionResult) {
|
481
|
-
return (_jsx(QueryBuilderGridResult, { queryBuilderState: queryBuilderState, executionResult: executionResult }));
|
482
|
-
}
|
483
|
-
else if (executionResult instanceof RawExecutionResult) {
|
484
|
-
const inputValue = executionResult.value === null
|
485
|
-
? 'null'
|
486
|
-
: executionResult.value.toString();
|
487
|
-
return (_jsx(CodeEditor, { language: CODE_EDITOR_LANGUAGE.TEXT, inputValue: inputValue, isReadOnly: true }));
|
488
|
-
}
|
489
|
-
return (_jsx(CodeEditor, { language: CODE_EDITOR_LANGUAGE.JSON, inputValue: JSON.stringify(extractExecutionResultValues(executionResult), null, DEFAULT_TAB_SIZE), isReadOnly: true }));
|
490
|
-
});
|
491
|
-
export const QueryBuilderResultPanel = observer((props) => {
|
492
|
-
const { queryBuilderState } = props;
|
493
|
-
const applicationStore = useApplicationStore();
|
494
|
-
const resultState = queryBuilderState.resultState;
|
495
|
-
const queryParametersState = queryBuilderState.parametersState;
|
496
|
-
const executionResult = resultState.executionResult;
|
497
|
-
const [showSqlModal, setShowSqlModal] = useState(false);
|
498
|
-
const relationalActivities = executionResult?.activities;
|
499
|
-
const executedSqls = relationalActivities
|
500
|
-
?.filter(filterByType(RelationalExecutionActivities))
|
501
|
-
.map((relationalActivity) => relationalActivity.sql);
|
502
|
-
let executedSql = '';
|
503
|
-
if (executedSqls?.length && executedSqls.length > 1) {
|
504
|
-
for (let i = 0; i < executedSqls.length; i++) {
|
505
|
-
executedSql += `\n--QUERY #${i + 1}\n`;
|
506
|
-
executedSql += `${executedSqls[i]}\n`;
|
507
|
-
}
|
508
|
-
}
|
509
|
-
else {
|
510
|
-
executedSql += executedSqls?.[0];
|
511
|
-
}
|
512
|
-
const fetchStructureImplementation = queryBuilderState.fetchStructureState.implementation;
|
513
|
-
const USER_ATTESTATION_MESSAGE = 'I attest that I am aware of the sensitive data leakage risk when exporting queried data. The data I export will only be used by me.';
|
514
|
-
const exportQueryResults = async (format) => {
|
515
|
-
if (queryBuilderState.parametersState.parameterStates.length) {
|
516
|
-
queryParametersState.parameterValuesEditorState.open(() => flowResult(resultState.exportData(format)).catch(applicationStore.alertUnhandledError), PARAMETER_SUBMIT_ACTION.EXPORT);
|
517
|
-
}
|
518
|
-
else {
|
519
|
-
await flowResult(resultState.exportData(format)).catch(applicationStore.alertUnhandledError);
|
520
|
-
}
|
521
|
-
};
|
522
|
-
const confirmExport = (format) => {
|
523
|
-
applicationStore.alertService.setActionAlertInfo({
|
524
|
-
message: USER_ATTESTATION_MESSAGE,
|
525
|
-
type: ActionAlertType.CAUTION,
|
526
|
-
actions: [
|
527
|
-
{
|
528
|
-
label: 'Accept',
|
529
|
-
type: ActionAlertActionType.PROCEED_WITH_CAUTION,
|
530
|
-
handler: applicationStore.guardUnhandledError(() => exportQueryResults(format)),
|
531
|
-
},
|
532
|
-
{
|
533
|
-
label: 'Decline',
|
534
|
-
type: ActionAlertActionType.PROCEED,
|
535
|
-
default: true,
|
536
|
-
},
|
537
|
-
],
|
538
|
-
});
|
539
|
-
};
|
540
|
-
const allValidationIssues = queryBuilderState.allValidationIssues;
|
541
|
-
const isSupportedQueryValid = allValidationIssues.length === 0;
|
542
|
-
const isQueryValid = !queryBuilderState.isQuerySupported || isSupportedQueryValid;
|
543
|
-
const isQueryValidForAdvancedMode = isQueryValid &&
|
544
|
-
queryBuilderState.fetchStructureState.implementation instanceof
|
545
|
-
QueryBuilderTDSState;
|
546
|
-
const runQuery = () => {
|
547
|
-
resultState.setSelectedCells([]);
|
548
|
-
resultState.pressedRunQuery.inProgress();
|
549
|
-
if (queryParametersState.parameterStates.length) {
|
550
|
-
queryParametersState.parameterValuesEditorState.open(() => flowResult(resultState.runQuery()).catch(applicationStore.alertUnhandledError), PARAMETER_SUBMIT_ACTION.RUN);
|
551
|
-
}
|
552
|
-
else {
|
553
|
-
flowResult(resultState.runQuery()).catch(applicationStore.alertUnhandledError);
|
554
|
-
}
|
555
|
-
resultState.pressedRunQuery.complete();
|
556
|
-
};
|
557
|
-
const cancelQuery = applicationStore.guardUnhandledError(() => flowResult(resultState.cancelQuery()));
|
558
|
-
const generatePlan = applicationStore.guardUnhandledError(() => flowResult(resultState.generatePlan(false)));
|
559
|
-
const debugPlanGeneration = applicationStore.guardUnhandledError(() => flowResult(resultState.generatePlan(true)));
|
560
|
-
const allowSettingPreviewLimit = queryBuilderState.isQuerySupported;
|
561
|
-
const allowSettingAdvancedMode = queryBuilderState.isQuerySupported;
|
562
|
-
const copyExpression = (value) => {
|
563
|
-
applicationStore.clipboardService
|
564
|
-
.copyTextToClipboard(value)
|
565
|
-
.then(() => applicationStore.notificationService.notifySuccess('SQL Query copied', undefined, 2500))
|
566
|
-
.catch(applicationStore.alertUnhandledError);
|
567
|
-
};
|
568
|
-
const isRunQueryDisabled = !isQueryValid ||
|
569
|
-
resultState.isGeneratingPlan ||
|
570
|
-
resultState.pressedRunQuery.isInProgress;
|
571
|
-
const getResultSetDescription = (_executionResult) => {
|
572
|
-
const queryDuration = resultState.executionDuration
|
573
|
-
? prettyDuration(resultState.executionDuration, {
|
574
|
-
ms: true,
|
575
|
-
})
|
576
|
-
: undefined;
|
577
|
-
if (_executionResult instanceof TDSExecutionResult) {
|
578
|
-
const rowLength = _executionResult.result.rows.length;
|
579
|
-
return `${rowLength} row(s)${queryDuration ? ` in ${queryDuration}` : ''}`;
|
580
|
-
}
|
581
|
-
if (!queryDuration) {
|
582
|
-
return undefined;
|
583
|
-
}
|
584
|
-
return `query ran in ${queryDuration}`;
|
585
|
-
};
|
586
|
-
const resultDescription = executionResult
|
587
|
-
? getResultSetDescription(executionResult)
|
588
|
-
: undefined;
|
589
|
-
const [previewLimitValue, setPreviewLimitValue] = useState(resultState.previewLimit);
|
590
|
-
const changePreviewLimit = (event) => {
|
591
|
-
setPreviewLimitValue(parseInt(event.target.value, 10));
|
592
|
-
};
|
593
|
-
const inputRef = useRef(null);
|
594
|
-
const getPreviewLimit = () => {
|
595
|
-
if (isNaN(previewLimitValue) || previewLimitValue === 0) {
|
596
|
-
setPreviewLimitValue(1);
|
597
|
-
queryBuilderState.resultState.setPreviewLimit(1);
|
598
|
-
}
|
599
|
-
else {
|
600
|
-
queryBuilderState.resultState.setPreviewLimit(previewLimitValue);
|
601
|
-
}
|
602
|
-
};
|
603
|
-
const onKeyDown = (event) => {
|
604
|
-
if (event.code === 'Enter') {
|
605
|
-
getPreviewLimit();
|
606
|
-
inputRef.current?.focus();
|
607
|
-
}
|
608
|
-
else if (event.code === 'Escape') {
|
609
|
-
inputRef.current?.select();
|
610
|
-
}
|
611
|
-
};
|
612
|
-
const toggleIsAdvancedModeEnabled = () => {
|
613
|
-
resultState.setExecutionResult(undefined);
|
614
|
-
queryBuilderState.setIsAdvancedModeEnabled(!queryBuilderState.isAdvancedModeEnabled);
|
615
|
-
};
|
616
|
-
return (_jsxs("div", { "data-testid": QUERY_BUILDER_TEST_ID.QUERY_BUILDER_RESULT_PANEL, className: "panel query-builder__result", children: [showSqlModal && executedSqls && (_jsx(Dialog, { open: Boolean(showSqlModal), onClose: () => setShowSqlModal(false), children: _jsxs(Modal, { className: "editor-modal", darkMode: true, children: [_jsx(ModalHeader, { title: "Executed SQL Query" }), _jsx(ModalBody, { className: "query-builder__sql__modal", children: _jsxs(_Fragment, { children: [_jsx(CodeEditor, { inputValue: tryToFormatSql(executedSql), isReadOnly: true, language: CODE_EDITOR_LANGUAGE.SQL, hideMinimap: true }), _jsx(PanelDivider, {})] }) }), _jsxs(ModalFooter, { children: [_jsx(ModalFooterButton, { formatText: false, onClick: () => copyExpression(executedSql), text: "Copy SQL to Clipboard" }), _jsx(ModalFooterButton, { onClick: () => setShowSqlModal(false), text: "Close" })] })] }) })), _jsxs("div", { className: "panel__header", children: [_jsxs("div", { className: "panel__header__title", children: [_jsx("div", { className: "panel__header__title__label", children: "result" }), executedSqls && (_jsx(Button, { onClick: () => setShowSqlModal(true), title: "Executed SQL", className: "query-builder__result__sql__actions", children: _jsx(SQLIcon, {}) })), resultState.pressedRunQuery.isInProgress && (_jsx("div", { className: "panel__header__title__label__status", children: "Running Query..." })), _jsx("div", { "data-testid": QUERY_BUILDER_TEST_ID.QUERY_BUILDER_RESULT_ANALYTICS, className: "query-builder__result__analytics", children: resultDescription ?? '' }), executionResult && resultState.checkForStaleResults && (_jsxs("div", { className: "query-builder__result__stale-status", children: [_jsx("div", { className: "query-builder__result__stale-status__icon", children: _jsx(ExclamationTriangleIcon, {}) }), _jsx("div", { className: "query-builder__result__stale-status__label", children: "Preview data might be stale" })] }))] }), _jsxs("div", { className: "panel__header__actions query-builder__result__header__actions", children: [allowSettingAdvancedMode && (_jsxs("div", { className: "query-builder__result__advanced__mode", children: [_jsxs("div", { className: "query-builder__result__advanced__mode__label", children: ["Advanced Mode", _jsx(DocumentationLink, { title: "The grid in advanced mode performs all operations like grouping, sorting, filtering, etc after initial query execution locally withought reaching out to server. This limits the number of rows to smaller number so they can fit in memory", documentationKey: QUERY_BUILDER_DOCUMENTATION_KEY.QUESTION_HOW_TO_USE_ADVANCED_GRID_MODE })] }), _jsx("button", { className: clsx('query-builder__result__advanced__mode__toggler__btn', {
|
617
|
-
'query-builder__result__advanced__mode__toggler__btn--toggled': queryBuilderState.isAdvancedModeEnabled,
|
618
|
-
}), disabled: !isQueryValidForAdvancedMode, onClick: toggleIsAdvancedModeEnabled, tabIndex: -1, children: queryBuilderState.isAdvancedModeEnabled ? (_jsx(CheckSquareIcon, {})) : (_jsx(SquareIcon, {})) })] })), allowSettingPreviewLimit && (_jsxs("div", { className: "query-builder__result__limit", children: [_jsx("div", { className: "query-builder__result__limit__label", children: "preview limit" }), _jsx("input", { ref: inputRef, className: "input--dark query-builder__result__limit__input", spellCheck: false, type: "number", value: previewLimitValue, onChange: changePreviewLimit, onBlur: getPreviewLimit, onKeyDown: onKeyDown, disabled: !isQueryValid })] })), _jsx("div", { className: "query-builder__result__execute-btn btn__dropdown-combo btn__dropdown-combo--primary", children: resultState.isRunningQuery ? (_jsx("button", { className: "btn__dropdown-combo__canceler", onClick: cancelQuery, tabIndex: -1, disabled: !isQueryValid, children: _jsxs("div", { className: "btn--dark btn--caution btn__dropdown-combo__canceler__label", children: [_jsx(PauseCircleIcon, { className: "btn__dropdown-combo__canceler__label__icon" }), _jsx("div", { className: "btn__dropdown-combo__canceler__label__title", children: "Stop" })] }) })) : (_jsxs(_Fragment, { children: [_jsxs("button", { className: "btn__dropdown-combo__label", onClick: runQuery, tabIndex: -1, title: allValidationIssues.length
|
619
|
-
? `Query is not valid:\n${allValidationIssues
|
620
|
-
.map((issue) => `\u2022 ${issue}`)
|
621
|
-
.join('\n')}`
|
622
|
-
: undefined, disabled: isRunQueryDisabled, children: [_jsx(PlayIcon, { className: "btn__dropdown-combo__label__icon" }), _jsx("div", { className: "btn__dropdown-combo__label__title", children: "Run Query" })] }), _jsx(DropdownMenu, { className: "btn__dropdown-combo__dropdown-btn", disabled: isRunQueryDisabled, content: _jsxs(MenuContent, { children: [_jsx(MenuContentItem, { className: "btn__dropdown-combo__option", onClick: generatePlan, disabled: isRunQueryDisabled, children: "Generate Plan" }), _jsx(MenuContentItem, { className: "btn__dropdown-combo__option", onClick: debugPlanGeneration, disabled: isRunQueryDisabled, children: "Debug" })] }), menuProps: {
|
623
|
-
anchorOrigin: { vertical: 'bottom', horizontal: 'right' },
|
624
|
-
transformOrigin: { vertical: 'top', horizontal: 'right' },
|
625
|
-
}, children: _jsx(CaretDownIcon, {}) })] })) }), _jsxs(DropdownMenu, { className: "query-builder__result__export__dropdown", title: "Export", disabled: !isQueryValid, content: _jsxs(MenuContent, { children: [Object.values(fetchStructureImplementation.exportDataFormatOptions).map((format) => (_jsx(MenuContentItem, { className: "query-builder__result__export__dropdown__menu__item", onClick: () => confirmExport(format), children: format }, format))), _jsx(MenuContentItem, { className: "query-builder__result__export__dropdown__menu__item", onClick: () => resultState.setIsQueryUsageViewerOpened(true), disabled: queryBuilderState.changeDetectionState.hasChanged, children: "View Query Usage..." })] }), menuProps: {
|
626
|
-
anchorOrigin: { vertical: 'bottom', horizontal: 'right' },
|
627
|
-
transformOrigin: { vertical: 'top', horizontal: 'right' },
|
628
|
-
elevation: 7,
|
629
|
-
}, children: [_jsx("div", { className: "query-builder__result__export__dropdown__label", children: "Export" }), _jsx("div", { className: "query-builder__result__export__dropdown__trigger", children: _jsx(CaretDownIcon, {}) })] }), resultState.isQueryUsageViewerOpened && (_jsx(QueryUsageViewer, { resultState: resultState }))] })] }), _jsxs(PanelContent, { children: [_jsx(PanelLoadingIndicator, { isLoading: resultState.isRunningQuery ||
|
630
|
-
resultState.isGeneratingPlan ||
|
631
|
-
resultState.exportDataState.isInProgress }), !executionResult && (_jsx(BlankPanelContent, { children: "Build or load a valid query first" })), executionResult && (_jsx("div", { className: "query-builder__result__values", children: _jsx(QueryBuilderResultValues, { executionResult: executionResult, queryBuilderState: queryBuilderState }) }))] }), _jsx(ExecutionPlanViewer, { executionPlanState: resultState.executionPlanState })] }));
|
632
|
-
});
|
633
|
-
//# sourceMappingURL=QueryBuilderResultPanel.js.map
|