@finos/legend-query-builder 4.14.69 → 4.14.71

Sign up to get free protection for your applications and to get access to all the features.
Files changed (100) hide show
  1. package/lib/__lib__/QueryBuilderTesting.d.ts +1 -0
  2. package/lib/__lib__/QueryBuilderTesting.d.ts.map +1 -1
  3. package/lib/__lib__/QueryBuilderTesting.js +1 -0
  4. package/lib/__lib__/QueryBuilderTesting.js.map +1 -1
  5. package/lib/components/QueryBuilderConstantExpressionPanel.d.ts.map +1 -1
  6. package/lib/components/QueryBuilderConstantExpressionPanel.js +2 -1
  7. package/lib/components/QueryBuilderConstantExpressionPanel.js.map +1 -1
  8. package/lib/components/explorer/QueryBuilderExplorerPanel.d.ts +1 -0
  9. package/lib/components/explorer/QueryBuilderExplorerPanel.d.ts.map +1 -1
  10. package/lib/components/explorer/QueryBuilderExplorerPanel.js +87 -52
  11. package/lib/components/explorer/QueryBuilderExplorerPanel.js.map +1 -1
  12. package/lib/components/explorer/QueryBuilderPropertySearchPanel.d.ts +4 -0
  13. package/lib/components/explorer/QueryBuilderPropertySearchPanel.d.ts.map +1 -1
  14. package/lib/components/explorer/QueryBuilderPropertySearchPanel.js +172 -108
  15. package/lib/components/explorer/QueryBuilderPropertySearchPanel.js.map +1 -1
  16. package/lib/components/fetch-structure/QueryBuilderPostFilterPanel.d.ts.map +1 -1
  17. package/lib/components/fetch-structure/QueryBuilderPostFilterPanel.js +2 -1
  18. package/lib/components/fetch-structure/QueryBuilderPostFilterPanel.js.map +1 -1
  19. package/lib/components/fetch-structure/QueryBuilderTDSPanel.d.ts.map +1 -1
  20. package/lib/components/fetch-structure/QueryBuilderTDSPanel.js +29 -18
  21. package/lib/components/fetch-structure/QueryBuilderTDSPanel.js.map +1 -1
  22. package/lib/components/fetch-structure/QueryBuilderTDSWindowPanel.d.ts.map +1 -1
  23. package/lib/components/fetch-structure/QueryBuilderTDSWindowPanel.js +13 -4
  24. package/lib/components/fetch-structure/QueryBuilderTDSWindowPanel.js.map +1 -1
  25. package/lib/components/filter/QueryBuilderFilterPanel.d.ts.map +1 -1
  26. package/lib/components/filter/QueryBuilderFilterPanel.js +4 -3
  27. package/lib/components/filter/QueryBuilderFilterPanel.js.map +1 -1
  28. package/lib/components/result/QueryBuilderResultPanel.d.ts +12 -0
  29. package/lib/components/result/QueryBuilderResultPanel.d.ts.map +1 -1
  30. package/lib/components/result/QueryBuilderResultPanel.js +60 -8
  31. package/lib/components/result/QueryBuilderResultPanel.js.map +1 -1
  32. package/lib/components/shared/QueryBuilderFilterHelper.d.ts.map +1 -1
  33. package/lib/components/shared/QueryBuilderFilterHelper.js +3 -0
  34. package/lib/components/shared/QueryBuilderFilterHelper.js.map +1 -1
  35. package/lib/components/shared/QueryBuilderPropertyInfoTooltip.d.ts +11 -0
  36. package/lib/components/shared/QueryBuilderPropertyInfoTooltip.d.ts.map +1 -1
  37. package/lib/components/shared/QueryBuilderPropertyInfoTooltip.js +6 -3
  38. package/lib/components/shared/QueryBuilderPropertyInfoTooltip.js.map +1 -1
  39. package/lib/graph-manager/QueryBuilderConfig.d.ts +4 -0
  40. package/lib/graph-manager/QueryBuilderConfig.d.ts.map +1 -1
  41. package/lib/graph-manager/QueryBuilderConfig.js +5 -0
  42. package/lib/graph-manager/QueryBuilderConfig.js.map +1 -1
  43. package/lib/index.css +2 -2
  44. package/lib/index.css.map +1 -1
  45. package/lib/package.json +1 -1
  46. package/lib/stores/QueryBuilderConstantsState.d.ts +1 -0
  47. package/lib/stores/QueryBuilderConstantsState.d.ts.map +1 -1
  48. package/lib/stores/QueryBuilderConstantsState.js +6 -1
  49. package/lib/stores/QueryBuilderConstantsState.js.map +1 -1
  50. package/lib/stores/QueryBuilderResultState.d.ts +11 -3
  51. package/lib/stores/QueryBuilderResultState.d.ts.map +1 -1
  52. package/lib/stores/QueryBuilderResultState.js +47 -4
  53. package/lib/stores/QueryBuilderResultState.js.map +1 -1
  54. package/lib/stores/QueryBuilderValueSpecificationBuilderHelper.d.ts +4 -0
  55. package/lib/stores/QueryBuilderValueSpecificationBuilderHelper.d.ts.map +1 -1
  56. package/lib/stores/explorer/QueryBuilderExplorerState.d.ts +3 -1
  57. package/lib/stores/explorer/QueryBuilderExplorerState.d.ts.map +1 -1
  58. package/lib/stores/explorer/QueryBuilderExplorerState.js +63 -8
  59. package/lib/stores/explorer/QueryBuilderExplorerState.js.map +1 -1
  60. package/lib/stores/explorer/QueryBuilderFuzzySearchAdvancedConfigState.d.ts +24 -0
  61. package/lib/stores/explorer/QueryBuilderFuzzySearchAdvancedConfigState.d.ts.map +1 -0
  62. package/lib/stores/explorer/QueryBuilderFuzzySearchAdvancedConfigState.js +39 -0
  63. package/lib/stores/explorer/QueryBuilderFuzzySearchAdvancedConfigState.js.map +1 -0
  64. package/lib/stores/explorer/QueryBuilderPropertySearchState.d.ts +8 -4
  65. package/lib/stores/explorer/QueryBuilderPropertySearchState.d.ts.map +1 -1
  66. package/lib/stores/explorer/QueryBuilderPropertySearchState.js +204 -114
  67. package/lib/stores/explorer/QueryBuilderPropertySearchState.js.map +1 -1
  68. package/lib/stores/fetch-structure/tds/post-filter/QueryBuilderPostFilterState.d.ts.map +1 -1
  69. package/lib/stores/fetch-structure/tds/post-filter/QueryBuilderPostFilterState.js +8 -1
  70. package/lib/stores/fetch-structure/tds/post-filter/QueryBuilderPostFilterState.js.map +1 -1
  71. package/lib/stores/fetch-structure/tds/projection/QueryBuilderProjectionValueSpecificationBuilder.d.ts.map +1 -1
  72. package/lib/stores/fetch-structure/tds/projection/QueryBuilderProjectionValueSpecificationBuilder.js +12 -1
  73. package/lib/stores/fetch-structure/tds/projection/QueryBuilderProjectionValueSpecificationBuilder.js.map +1 -1
  74. package/lib/stores/filter/QueryBuilderFilterState.d.ts +8 -1
  75. package/lib/stores/filter/QueryBuilderFilterState.d.ts.map +1 -1
  76. package/lib/stores/filter/QueryBuilderFilterState.js +27 -10
  77. package/lib/stores/filter/QueryBuilderFilterState.js.map +1 -1
  78. package/package.json +8 -8
  79. package/src/__lib__/QueryBuilderTesting.ts +1 -0
  80. package/src/components/QueryBuilderConstantExpressionPanel.tsx +2 -1
  81. package/src/components/explorer/QueryBuilderExplorerPanel.tsx +220 -114
  82. package/src/components/explorer/QueryBuilderPropertySearchPanel.tsx +618 -388
  83. package/src/components/fetch-structure/QueryBuilderPostFilterPanel.tsx +5 -2
  84. package/src/components/fetch-structure/QueryBuilderTDSPanel.tsx +78 -44
  85. package/src/components/fetch-structure/QueryBuilderTDSWindowPanel.tsx +63 -10
  86. package/src/components/filter/QueryBuilderFilterPanel.tsx +4 -2
  87. package/src/components/result/QueryBuilderResultPanel.tsx +207 -20
  88. package/src/components/shared/QueryBuilderFilterHelper.ts +8 -0
  89. package/src/components/shared/QueryBuilderPropertyInfoTooltip.tsx +13 -3
  90. package/src/graph-manager/QueryBuilderConfig.ts +6 -0
  91. package/src/stores/QueryBuilderConstantsState.ts +16 -1
  92. package/src/stores/QueryBuilderResultState.ts +64 -10
  93. package/src/stores/QueryBuilderValueSpecificationBuilderHelper.ts +5 -0
  94. package/src/stores/explorer/QueryBuilderExplorerState.ts +92 -8
  95. package/src/stores/explorer/QueryBuilderFuzzySearchAdvancedConfigState.ts +46 -0
  96. package/src/stores/explorer/QueryBuilderPropertySearchState.ts +280 -142
  97. package/src/stores/fetch-structure/tds/post-filter/QueryBuilderPostFilterState.ts +8 -1
  98. package/src/stores/fetch-structure/tds/projection/QueryBuilderProjectionValueSpecificationBuilder.ts +15 -2
  99. package/src/stores/filter/QueryBuilderFilterState.ts +34 -11
  100. package/tsconfig.json +1 -0
@@ -317,7 +317,10 @@ const QueryBuilderPostFilterConditionEditor = observer(
317
317
  const conditionValueType =
318
318
  node.condition.leftConditionValue.getColumnType();
319
319
  if (canDropTypeOntoNodeValue(itemType, node.condition)) {
320
- if (type === QUERY_BUILDER_PROJECTION_COLUMN_DND_TYPE) {
320
+ if (
321
+ type === QUERY_BUILDER_PROJECTION_COLUMN_DND_TYPE ||
322
+ type === QUERY_BUILDER_WINDOW_COLUMN_DND_TYPE
323
+ ) {
321
324
  const columnState = (item as QueryBuilderProjectionColumnDragSource)
322
325
  .columnState;
323
326
  node.condition.setRightConditionVal(
@@ -1047,7 +1050,7 @@ const QueryBuilderPostFilterPanelContent = observer(
1047
1050
  [applicationStore, handleDrop],
1048
1051
  );
1049
1052
 
1050
- const addPostFilterRef = useRef<HTMLInputElement>(null);
1053
+ const addPostFilterRef = useRef<HTMLDivElement>(null);
1051
1054
  dropTargetConnector(addPostFilterRef);
1052
1055
 
1053
1056
  return (
@@ -119,6 +119,41 @@ import {
119
119
  } from '../shared/QueryBuilderPropertyInfoTooltip.js';
120
120
  import { getNameOfValueSpecification } from '../shared/QueryBuilderVariableSelector.js';
121
121
  import { QueryBuilderAggregateOperator_Percentile } from '../../stores/fetch-structure/tds/aggregation/operators/QueryBuilderAggregateOperator_Percentile.js';
122
+ import {
123
+ getFurthestExistsNodeParent,
124
+ isExistsNodeChild,
125
+ QUERY_BUILDER_FILTER_DND_TYPE,
126
+ QueryBuilderFilterTreeConditionNodeData,
127
+ type QueryBuilderFilterConditionDragSource,
128
+ } from '../../stores/filter/QueryBuilderFilterState.js';
129
+ import { cloneAbstractPropertyExpression } from '../../stores/shared/ValueSpecificationEditorHelper.js';
130
+ import { buildPropertyExpressionFromExistsNode } from '../filter/QueryBuilderFilterPanel.js';
131
+
132
+ const CAN_DROP_MAIN_GROUP_DND_TYPES = [
133
+ QUERY_BUILDER_EXPLORER_TREE_DND_TYPE.ENUM_PROPERTY,
134
+ QUERY_BUILDER_EXPLORER_TREE_DND_TYPE.PRIMITIVE_PROPERTY,
135
+ QUERY_BUILDER_FILTER_DND_TYPE.CONDITION,
136
+ QUERY_BUILDER_FUNCTION_DND_TYPE,
137
+ ];
138
+
139
+ const CAN_DROP_DERIVATION_PROJECTION_COLUMN_DND_TYPES = [
140
+ QUERY_BUILDER_EXPLORER_TREE_DND_TYPE.ROOT,
141
+ QUERY_BUILDER_EXPLORER_TREE_DND_TYPE.CLASS_PROPERTY,
142
+ QUERY_BUILDER_EXPLORER_TREE_DND_TYPE.ENUM_PROPERTY,
143
+ QUERY_BUILDER_EXPLORER_TREE_DND_TYPE.PRIMITIVE_PROPERTY,
144
+ QUERY_BUILDER_VARIABLE_DND_TYPE,
145
+ QUERY_BUILDER_FUNCTION_DND_TYPE,
146
+ ];
147
+
148
+ type QueryBuilderTDSPanelDropTarget =
149
+ | QueryBuilderExplorerTreeDragSource
150
+ | QueryBuilderFunctionsExplorerDragSource
151
+ | QueryBuilderFilterConditionDragSource;
152
+
153
+ type QueryBuilderDerivationProjectionColumnDropTarget =
154
+ | QueryBuilderExplorerTreeDragSource
155
+ | QueryBuilderVariableDragSource
156
+ | QueryBuilderFunctionsExplorerDragSource;
122
157
 
123
158
  const QueryBuilderProjectionColumnContextMenu = observer(
124
159
  forwardRef<
@@ -192,10 +227,7 @@ const QueryBuilderDerivationProjectionColumnEditor = observer(
192
227
  };
193
228
  const handleDrop = useCallback(
194
229
  (
195
- item:
196
- | QueryBuilderExplorerTreeDragSource
197
- | QueryBuilderVariableDragSource
198
- | QueryBuilderFunctionsExplorerDragSource,
230
+ item: QueryBuilderDerivationProjectionColumnDropTarget,
199
231
  type: string,
200
232
  ): void => {
201
233
  if (type === QUERY_BUILDER_VARIABLE_DND_TYPE) {
@@ -224,28 +256,18 @@ const QueryBuilderDerivationProjectionColumnEditor = observer(
224
256
  },
225
257
  [projectionColumnState],
226
258
  );
227
- const [, dropConnector] = useDrop<
228
- | QueryBuilderExplorerTreeDragSource
229
- | QueryBuilderVariableDragSource
230
- | QueryBuilderFunctionsExplorerDragSource
231
- >(
232
- () => ({
233
- accept: [
234
- QUERY_BUILDER_EXPLORER_TREE_DND_TYPE.ROOT,
235
- QUERY_BUILDER_EXPLORER_TREE_DND_TYPE.CLASS_PROPERTY,
236
- QUERY_BUILDER_EXPLORER_TREE_DND_TYPE.ENUM_PROPERTY,
237
- QUERY_BUILDER_EXPLORER_TREE_DND_TYPE.PRIMITIVE_PROPERTY,
238
- QUERY_BUILDER_VARIABLE_DND_TYPE,
239
- QUERY_BUILDER_FUNCTION_DND_TYPE,
240
- ],
241
- drop: (item, monitor): void => {
242
- if (!monitor.didDrop()) {
243
- handleDrop(item, monitor.getItemType() as string);
244
- } // prevent drop event propagation to accomondate for nested DnD
245
- },
246
- }),
247
- [handleDrop],
248
- );
259
+ const [, dropConnector] =
260
+ useDrop<QueryBuilderDerivationProjectionColumnDropTarget>(
261
+ () => ({
262
+ accept: CAN_DROP_DERIVATION_PROJECTION_COLUMN_DND_TYPES,
263
+ drop: (item, monitor): void => {
264
+ if (!monitor.didDrop()) {
265
+ handleDrop(item, monitor.getItemType() as string);
266
+ } // prevent drop event propagation to accomondate for nested DnD
267
+ },
268
+ }),
269
+ [handleDrop],
270
+ );
249
271
 
250
272
  return (
251
273
  <div
@@ -1230,12 +1252,7 @@ export const QueryBuilderTDSPanel = observer(
1230
1252
 
1231
1253
  // Drag and Drop
1232
1254
  const handleDrop = useCallback(
1233
- (
1234
- item:
1235
- | QueryBuilderExplorerTreeDragSource
1236
- | QueryBuilderFunctionsExplorerDragSource,
1237
- type: string,
1238
- ): void => {
1255
+ (item: QueryBuilderTDSPanelDropTarget, type: string): void => {
1239
1256
  switch (type) {
1240
1257
  case QUERY_BUILDER_FUNCTION_DND_TYPE: {
1241
1258
  const derivationProjectionColumn =
@@ -1267,6 +1284,30 @@ export const QueryBuilderTDSPanel = observer(
1267
1284
  ),
1268
1285
  );
1269
1286
  break;
1287
+ case QUERY_BUILDER_FILTER_DND_TYPE.CONDITION:
1288
+ if (item.node instanceof QueryBuilderFilterTreeConditionNodeData) {
1289
+ const propertyExpression = isExistsNodeChild(item.node)
1290
+ ? buildPropertyExpressionFromExistsNode(
1291
+ tdsState.queryBuilderState.filterState,
1292
+ guaranteeNonNullable(
1293
+ getFurthestExistsNodeParent(item.node),
1294
+ ),
1295
+ item.node,
1296
+ )
1297
+ : cloneAbstractPropertyExpression(
1298
+ item.node.condition.propertyExpressionState
1299
+ .propertyExpression,
1300
+ tdsState.queryBuilderState.observerContext,
1301
+ );
1302
+ tdsState.addColumn(
1303
+ new QueryBuilderSimpleProjectionColumnState(
1304
+ tdsState,
1305
+ propertyExpression,
1306
+ tdsState.queryBuilderState.explorerState.humanizePropertyName,
1307
+ ),
1308
+ );
1309
+ }
1310
+ break;
1270
1311
  default:
1271
1312
  break;
1272
1313
  }
@@ -1275,17 +1316,12 @@ export const QueryBuilderTDSPanel = observer(
1275
1316
  );
1276
1317
 
1277
1318
  const [{ isDragOver }, dropTargetConnector] = useDrop<
1278
- | QueryBuilderExplorerTreeDragSource
1279
- | QueryBuilderFunctionsExplorerDragSource,
1319
+ QueryBuilderTDSPanelDropTarget,
1280
1320
  void,
1281
1321
  { isDragOver: boolean }
1282
1322
  >(
1283
1323
  () => ({
1284
- accept: [
1285
- QUERY_BUILDER_EXPLORER_TREE_DND_TYPE.ENUM_PROPERTY,
1286
- QUERY_BUILDER_EXPLORER_TREE_DND_TYPE.PRIMITIVE_PROPERTY,
1287
- QUERY_BUILDER_FUNCTION_DND_TYPE,
1288
- ],
1324
+ accept: CAN_DROP_MAIN_GROUP_DND_TYPES,
1289
1325
  drop: (item, monitor): void => {
1290
1326
  if (!monitor.didDrop()) {
1291
1327
  handleDrop(item, monitor.getItemType() as string);
@@ -1315,11 +1351,9 @@ export const QueryBuilderTDSPanel = observer(
1315
1351
  const { isDroppable } = useDragLayer((monitor) => ({
1316
1352
  isDroppable:
1317
1353
  monitor.isDragging() &&
1318
- [
1319
- QUERY_BUILDER_EXPLORER_TREE_DND_TYPE.ENUM_PROPERTY,
1320
- QUERY_BUILDER_EXPLORER_TREE_DND_TYPE.PRIMITIVE_PROPERTY,
1321
- QUERY_BUILDER_FUNCTION_DND_TYPE,
1322
- ].includes(monitor.getItemType()?.toString() ?? ''),
1354
+ CAN_DROP_MAIN_GROUP_DND_TYPES.includes(
1355
+ monitor.getItemType()?.toString() ?? '',
1356
+ ),
1323
1357
  }));
1324
1358
 
1325
1359
  useEffect(() => {
@@ -48,6 +48,7 @@ import {
48
48
  PanelHeader,
49
49
  PanelHeaderActions,
50
50
  Panel,
51
+ DragPreviewLayer,
51
52
  } from '@finos/legend-art';
52
53
  import {
53
54
  assertErrorThrown,
@@ -57,7 +58,12 @@ import {
57
58
  } from '@finos/legend-shared';
58
59
  import { observer } from 'mobx-react-lite';
59
60
  import { forwardRef, useCallback, useRef, useState } from 'react';
60
- import { type DropTargetMonitor, useDrag, useDrop } from 'react-dnd';
61
+ import {
62
+ type DropTargetMonitor,
63
+ useDrag,
64
+ useDragLayer,
65
+ useDrop,
66
+ } from 'react-dnd';
61
67
  import type { QueryBuilderTDS_WindowOperator } from '../../stores/fetch-structure/tds/window/operators/QueryBuilderTDS_WindowOperator.js';
62
68
  import {
63
69
  type QueryBuilderWindowState,
@@ -75,6 +81,7 @@ import type { QueryBuilderTDSState } from '../../stores/fetch-structure/tds/Quer
75
81
  import { QUERY_BUILDER_TEST_ID } from '../../__lib__/QueryBuilderTesting.js';
76
82
  import { QueryBuilderPanelIssueCountBadge } from '../shared/QueryBuilderPanelIssueCountBadge.js';
77
83
  import { COLUMN_SORT_TYPE } from '../../graph/QueryBuilderMetaModelConst.js';
84
+ import { CAN_DROP_MAIN_GROUP_DND_TYPES } from './QueryBuilderPostFilterPanel.js';
78
85
 
79
86
  // helpers
80
87
  const createWindowColumnState = (
@@ -965,6 +972,10 @@ const QueryBuilderWindowColumnEditor = observer(
965
972
  ref={ref}
966
973
  className="query-builder__olap__column"
967
974
  showPlaceholder={isBeingDragged}
975
+ placeholder={
976
+ <div className="query-builder__olap__column__placeholder" />
977
+ }
978
+ placeholderContainerClassName="query-builder__olap__column__placeholder__container"
968
979
  >
969
980
  <ContextMenu
970
981
  content={
@@ -1236,6 +1247,7 @@ export const QueryBuilderTDSWindowPanel = observer(
1236
1247
  tdsWindowState.setEditColumn(newWindowState);
1237
1248
  }
1238
1249
  };
1250
+
1239
1251
  // Drag and Drop
1240
1252
  const handleDrop = useCallback(
1241
1253
  async (item: QueryBuilderWindowDropTarget): Promise<void> => {
@@ -1253,6 +1265,7 @@ export const QueryBuilderTDSWindowPanel = observer(
1253
1265
  },
1254
1266
  [applicationStore, tdsWindowState],
1255
1267
  );
1268
+
1256
1269
  const [{ isDragOver }, dropTargetConnector] = useDrop<
1257
1270
  QueryBuilderWindowDropTarget,
1258
1271
  void,
@@ -1274,6 +1287,18 @@ export const QueryBuilderTDSWindowPanel = observer(
1274
1287
  }),
1275
1288
  [applicationStore, handleDrop],
1276
1289
  );
1290
+
1291
+ const { isDroppable } = useDragLayer((monitor) => ({
1292
+ isDroppable:
1293
+ monitor.isDragging() &&
1294
+ CAN_DROP_MAIN_GROUP_DND_TYPES.includes(
1295
+ monitor.getItemType()?.toString() ?? '',
1296
+ ),
1297
+ }));
1298
+
1299
+ const addWindowColumnRef = useRef<HTMLDivElement>(null);
1300
+ dropTargetConnector(addWindowColumnRef);
1301
+
1277
1302
  return (
1278
1303
  <Panel>
1279
1304
  <div
@@ -1301,7 +1326,8 @@ export const QueryBuilderTDSWindowPanel = observer(
1301
1326
  </PanelHeader>
1302
1327
  <PanelContent>
1303
1328
  <PanelDropZone
1304
- isDragOver={isDragOver}
1329
+ isDragOver={isDragOver && tdsWindowState.isEmpty}
1330
+ isDroppable={isDroppable && tdsWindowState.isEmpty}
1305
1331
  dropTargetConnector={dropTargetConnector}
1306
1332
  >
1307
1333
  {tdsWindowState.isEmpty && (
@@ -1311,16 +1337,43 @@ export const QueryBuilderTDSWindowPanel = observer(
1311
1337
  />
1312
1338
  )}
1313
1339
  {!tdsWindowState.isEmpty && (
1340
+ <>
1341
+ <DragPreviewLayer
1342
+ labelGetter={(
1343
+ item: QueryBuilderWindowColumnDragSource,
1344
+ ): string =>
1345
+ item.columnState.columnName === ''
1346
+ ? '(unknown)'
1347
+ : item.columnState.columnName
1348
+ }
1349
+ types={[QUERY_BUILDER_WINDOW_COLUMN_DND_TYPE]}
1350
+ />
1351
+ <div
1352
+ data-testid={QUERY_BUILDER_TEST_ID.QUERY_BUILDER_TDS}
1353
+ className="query-builder__olap__columns"
1354
+ >
1355
+ {tdsWindowState.windowColumns.map((col) => (
1356
+ <QueryBuilderWindowColumnEditor
1357
+ windowColumnState={col}
1358
+ key={col.uuid}
1359
+ />
1360
+ ))}
1361
+ </div>
1362
+ </>
1363
+ )}
1364
+ {isDroppable && !tdsWindowState.isEmpty && (
1314
1365
  <div
1315
- data-testid={QUERY_BUILDER_TEST_ID.QUERY_BUILDER_TDS}
1316
- className="query-builder__olap__columns"
1366
+ ref={addWindowColumnRef}
1367
+ className="query-builder__olap__free-drop-zone__container"
1317
1368
  >
1318
- {tdsWindowState.windowColumns.map((col) => (
1319
- <QueryBuilderWindowColumnEditor
1320
- windowColumnState={col}
1321
- key={col.uuid}
1322
- />
1323
- ))}
1369
+ <PanelEntryDropZonePlaceholder
1370
+ isDragOver={isDragOver}
1371
+ isDroppable={isDroppable}
1372
+ className="query-builder__olap__free-drop-zone"
1373
+ label="Add new window function column"
1374
+ >
1375
+ <></>
1376
+ </PanelEntryDropZonePlaceholder>
1324
1377
  </div>
1325
1378
  )}
1326
1379
  </PanelDropZone>
@@ -68,6 +68,7 @@ import {
68
68
  FilterPropertyExpressionStateConditionValueState,
69
69
  isCollectionProperty,
70
70
  type QueryBuilderFilterValueDropTarget,
71
+ isExistsNodeChild,
71
72
  } from '../../stores/filter/QueryBuilderFilterState.js';
72
73
  import { useDrag, useDragLayer, useDrop } from 'react-dnd';
73
74
  import {
@@ -830,6 +831,7 @@ const QueryBuilderFilterConditionEditor = observer(
830
831
  const queryBuilderState = node.condition.filterState.queryBuilderState;
831
832
  const rightConditionValue = node.condition.rightConditionValue;
832
833
  const applicationStore = useApplicationStore();
834
+ const isNodeExistsNodeChild = isExistsNodeChild(node);
833
835
 
834
836
  // Drag and Drop on filter condition value
835
837
  const handleDrop = useCallback(
@@ -845,7 +847,7 @@ const QueryBuilderFilterConditionEditor = observer(
845
847
  type === QUERY_BUILDER_EXPLORER_TREE_DND_TYPE.ENUM_PROPERTY ||
846
848
  type ===
847
849
  QUERY_BUILDER_EXPLORER_TREE_DND_TYPE.PRIMITIVE_PROPERTY) &&
848
- node.isExistsNodeChild
850
+ isNodeExistsNodeChild
849
851
  ) {
850
852
  throw new UnsupportedOperationError(
851
853
  'Collection filter does not support property for filter condition value.',
@@ -931,8 +933,8 @@ const QueryBuilderFilterConditionEditor = observer(
931
933
  [
932
934
  applicationStore,
933
935
  queryBuilderState,
936
+ isNodeExistsNodeChild,
934
937
  node.condition,
935
- node.isExistsNodeChild,
936
938
  ],
937
939
  );
938
940
 
@@ -44,6 +44,8 @@ import {
44
44
  ReportIcon,
45
45
  CubesLoadingIndicatorIcon,
46
46
  CubesLoadingIndicator,
47
+ InfoCircleIcon,
48
+ ShareBoxIcon,
47
49
  } from '@finos/legend-art';
48
50
  import { observer } from 'mobx-react-lite';
49
51
  import { flowResult } from 'mobx';
@@ -77,6 +79,108 @@ import { QueryBuilderTDSSimpleGridResult } from './tds/QueryBuilderTDSSimpleGrid
77
79
  import { getExecutedSqlFromExecutionResult } from './tds/QueryBuilderTDSResultShared.js';
78
80
  import { QueryBuilderTDSGridResult } from './tds/QueryBuilderTDSGridResult.js';
79
81
  import type { QueryBuilder_LegendApplicationPlugin_Extension } from '../../stores/QueryBuilder_LegendApplicationPlugin_Extension.js';
82
+ import type { QueryBuilderResultState } from '../../stores/QueryBuilderResultState.js';
83
+
84
+ const PERMISSION_ERRORS = ['permission denied', 'invalid user id or password'];
85
+
86
+ export const QueryBuilderExecutionErrorPanel = observer(
87
+ (props: {
88
+ resultState: QueryBuilderResultState;
89
+ executionError: string | Error;
90
+ }) => {
91
+ const { resultState, executionError } = props;
92
+ const queryBuilderState = resultState.queryBuilderState;
93
+ const errorMessage = executionError
94
+ ? queryBuilderState.applicationStore.notificationService.getErrorMessage(
95
+ executionError,
96
+ )
97
+ : '';
98
+ const isPermissionDeniedError = () =>
99
+ Boolean(
100
+ PERMISSION_ERRORS.find((e) => errorMessage?.toLowerCase().includes(e)),
101
+ );
102
+ const openCheckEntitlmentsEditor = (): void => {
103
+ queryBuilderState.checkEntitlementsState.setShowCheckEntitlementsViewer(
104
+ true,
105
+ );
106
+ };
107
+
108
+ return (
109
+ <>
110
+ {isPermissionDeniedError() && (
111
+ <div className="query-builder__result__permission-error">
112
+ <div className="query-builder__result__permission-error__header">
113
+ Entitlement / Authorization error - Please
114
+ </div>
115
+ <button
116
+ className="query-builder__result__permission-error__button"
117
+ disabled={
118
+ (queryBuilderState.isQuerySupported &&
119
+ queryBuilderState.fetchStructureState
120
+ .implementation instanceof QueryBuilderTDSState &&
121
+ queryBuilderState.fetchStructureState.implementation
122
+ .projectionColumns.length === 0) ||
123
+ !queryBuilderState.canBuildQuery
124
+ }
125
+ onClick={openCheckEntitlmentsEditor}
126
+ >
127
+ Click Here to Check Entitlements
128
+ </button>
129
+ </div>
130
+ )}
131
+ <div className="query-builder__result__execution-error">
132
+ <div className="query-builder__result__execution-error__header">
133
+ <span style={{ fontWeight: 'bold' }}>Error Execution Query</span>.
134
+ Please try again later or review options in application`s
135
+ <span style={{ fontWeight: 'bold' }}> Help</span> menu.
136
+ </div>
137
+ <div className="query-builder__result__execution-error__body">
138
+ {errorMessage}
139
+ </div>
140
+ </div>
141
+ </>
142
+ );
143
+ },
144
+ );
145
+
146
+ export const QueryBuilderEmptyExecutionResultPanel = observer(
147
+ (props: { queryBuilderState: QueryBuilderState }) => {
148
+ const { queryBuilderState } = props;
149
+
150
+ const openCheckEntitlmentsEditor = (): void => {
151
+ queryBuilderState.checkEntitlementsState.setShowCheckEntitlementsViewer(
152
+ true,
153
+ );
154
+ };
155
+
156
+ return (
157
+ <div className="query-builder__result__empty-result-warning">
158
+ <div className="query-builder__result__empty-result-warning__header">
159
+ Query returned no data
160
+ </div>
161
+ <div className="query-builder__result__empty-result-warning__body">
162
+ If you believe the query should return data, please
163
+ <button
164
+ className="query-builder__result__permission-error__button"
165
+ disabled={
166
+ (queryBuilderState.isQuerySupported &&
167
+ queryBuilderState.fetchStructureState.implementation instanceof
168
+ QueryBuilderTDSState &&
169
+ queryBuilderState.fetchStructureState.implementation
170
+ .projectionColumns.length === 0) ||
171
+ !queryBuilderState.canBuildQuery
172
+ }
173
+ onClick={openCheckEntitlmentsEditor}
174
+ >
175
+ Click Here to Check Entitlements
176
+ </button>
177
+ or See Help menu for more options
178
+ </div>
179
+ </div>
180
+ );
181
+ },
182
+ );
183
+ import { QueryBuilderBaseInfoTooltip } from '../shared/QueryBuilderPropertyInfoTooltip.js';
80
184
 
81
185
  export const QueryBuilderResultValues = observer(
82
186
  (props: {
@@ -85,20 +189,28 @@ export const QueryBuilderResultValues = observer(
85
189
  }) => {
86
190
  const { executionResult, queryBuilderState } = props;
87
191
  if (executionResult instanceof TDSExecutionResult) {
88
- if (queryBuilderState.config?.TEMPORARY__enableGridEnterpriseMode) {
192
+ if (executionResult.result.rows.length === 0) {
89
193
  return (
90
- <QueryBuilderTDSGridResult
194
+ <QueryBuilderEmptyExecutionResultPanel
91
195
  queryBuilderState={queryBuilderState}
92
- executionResult={executionResult}
93
196
  />
94
197
  );
95
198
  } else {
96
- return (
97
- <QueryBuilderTDSSimpleGridResult
98
- queryBuilderState={queryBuilderState}
99
- executionResult={executionResult}
100
- />
101
- );
199
+ if (queryBuilderState.config?.TEMPORARY__enableGridEnterpriseMode) {
200
+ return (
201
+ <QueryBuilderTDSGridResult
202
+ queryBuilderState={queryBuilderState}
203
+ executionResult={executionResult}
204
+ />
205
+ );
206
+ } else {
207
+ return (
208
+ <QueryBuilderTDSSimpleGridResult
209
+ queryBuilderState={queryBuilderState}
210
+ executionResult={executionResult}
211
+ />
212
+ );
213
+ }
102
214
  }
103
215
  } else if (executionResult instanceof RawExecutionResult) {
104
216
  const inputValue =
@@ -134,6 +246,7 @@ export const QueryBuilderResultPanel = observer(
134
246
  const resultState = queryBuilderState.resultState;
135
247
  const queryParametersState = queryBuilderState.parametersState;
136
248
  const executionResult = resultState.executionResult;
249
+ const resultLimit = resultState.getExecutionResultLimit();
137
250
  const [showSqlModal, setShowSqlModal] = useState(false);
138
251
  const executedSql = executionResult
139
252
  ? getExecutedSqlFromExecutionResult(executionResult, true)
@@ -211,6 +324,7 @@ export const QueryBuilderResultPanel = observer(
211
324
 
212
325
  const runQuery = (): void => {
213
326
  resultState.setSelectedCells([]);
327
+ resultState.setExecutionError(undefined);
214
328
  resultState.pressedRunQuery.inProgress();
215
329
  if (
216
330
  queryParametersState.parameterStates.length &&
@@ -278,8 +392,7 @@ export const QueryBuilderResultPanel = observer(
278
392
  })
279
393
  : undefined;
280
394
  if (_executionResult instanceof TDSExecutionResult) {
281
- const rowLength = _executionResult.result.rows.length;
282
- return `${rowLength} row(s)${
395
+ return `${_executionResult.result.rows.length} row(s)${
283
396
  queryDuration ? ` in ${queryDuration}` : ''
284
397
  }`;
285
398
  }
@@ -419,13 +532,62 @@ export const QueryBuilderResultPanel = observer(
419
532
  Running Query...
420
533
  </div>
421
534
  )}
422
-
423
- <div
424
- data-testid={QUERY_BUILDER_TEST_ID.QUERY_BUILDER_RESULT_ANALYTICS}
425
- className="query-builder__result__analytics"
426
- >
427
- {resultDescription ?? ''}
428
- </div>
535
+ {resultDescription && resultState.executionTraceId && (
536
+ <div
537
+ data-testid={
538
+ QUERY_BUILDER_TEST_ID.QUERY_BUILDER_RESULT_ANALYTICS
539
+ }
540
+ className="query-builder__result__analytics"
541
+ >
542
+ <QueryBuilderBaseInfoTooltip
543
+ title="Execution Result Analytics"
544
+ data={[
545
+ {
546
+ label: 'Trace',
547
+ value: 'available here',
548
+ actionButton: (
549
+ <div className="query-builder__tooltip__item__action">
550
+ <button
551
+ disabled={
552
+ !queryBuilderState.config?.zipkinTraceBaseURL
553
+ }
554
+ title={
555
+ queryBuilderState.config?.zipkinTraceBaseURL
556
+ ? ''
557
+ : 'No zipkin trace URL configured'
558
+ }
559
+ onClick={() => {
560
+ if (
561
+ queryBuilderState.config?.zipkinTraceBaseURL
562
+ ) {
563
+ applicationStore.navigationService.navigator.visitAddress(
564
+ queryBuilderState.config.zipkinTraceBaseURL +
565
+ resultState.executionTraceId,
566
+ );
567
+ }
568
+ }}
569
+ >
570
+ <ShareBoxIcon />
571
+ </button>
572
+ </div>
573
+ ),
574
+ },
575
+ ]}
576
+ >
577
+ <div className="editable-value">{resultDescription}</div>
578
+ </QueryBuilderBaseInfoTooltip>
579
+ </div>
580
+ )}
581
+ {resultDescription && !resultState.executionTraceId && (
582
+ <div
583
+ data-testid={
584
+ QUERY_BUILDER_TEST_ID.QUERY_BUILDER_RESULT_ANALYTICS
585
+ }
586
+ className="query-builder__result__analytics"
587
+ >
588
+ {resultDescription}
589
+ </div>
590
+ )}
429
591
  {executionResult && resultState.checkForStaleResults && (
430
592
  <div className="query-builder__result__stale-status">
431
593
  <div className="query-builder__result__stale-status__icon">
@@ -436,6 +598,25 @@ export const QueryBuilderResultPanel = observer(
436
598
  </div>
437
599
  </div>
438
600
  )}
601
+ {executionResult &&
602
+ executionResult instanceof TDSExecutionResult &&
603
+ resultState.isExecutionResultOverflowing && (
604
+ <div className="query-builder__result__stale-status">
605
+ <div className="query-builder__result__stale-status__icon">
606
+ <ExclamationTriangleIcon />
607
+ </div>
608
+ <div className="query-builder__result__stale-status__label">
609
+ Data below is not complete - query produces more rows than
610
+ the set grid preview limit
611
+ </div>
612
+ <div
613
+ className="query-builder__result__stale-status__icon"
614
+ title={`The preview limit is set to ${resultLimit}. The results in the grid below are being limited by this limit and running query with a higher limit would produce more rows. Export will not apply this limit.`}
615
+ >
616
+ <InfoCircleIcon />
617
+ </div>
618
+ </div>
619
+ )}
439
620
  </div>
440
621
  <div className="panel__header__actions query-builder__result__header__actions">
441
622
  {resultState.exportState.isInProgress && (
@@ -638,12 +819,18 @@ export const QueryBuilderResultPanel = observer(
638
819
  <CubesLoadingIndicator isLoading={isLoading}>
639
820
  <CubesLoadingIndicatorIcon />
640
821
  </CubesLoadingIndicator>
641
- {!executionResult && !isLoading && (
822
+ {!executionResult && !isLoading && !resultState.executionError && (
642
823
  <BlankPanelContent>
643
824
  Build or load a valid query first
644
825
  </BlankPanelContent>
645
826
  )}
646
- {executionResult && !isLoading && (
827
+ {!isLoading && resultState.executionError && (
828
+ <QueryBuilderExecutionErrorPanel
829
+ resultState={resultState}
830
+ executionError={resultState.executionError}
831
+ />
832
+ )}
833
+ {executionResult && !isLoading && !resultState.executionError && (
647
834
  <div className="query-builder__result__values">
648
835
  <QueryBuilderResultValues
649
836
  executionResult={executionResult}
@@ -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
  }