@finos/legend-query-builder 4.0.7 → 4.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. package/lib/__lib__/QueryBuilderColorTheme.js +1 -1
  2. package/lib/__lib__/QueryBuilderColorTheme.js.map +1 -1
  3. package/lib/__lib__/QueryBuilderDocumentation.js +1 -1
  4. package/lib/__lib__/QueryBuilderDocumentation.js.map +1 -1
  5. package/lib/__lib__/QueryBuilderEvent.js +3 -3
  6. package/lib/__lib__/QueryBuilderEvent.js.map +1 -1
  7. package/lib/__lib__/QueryBuilderSetting.js +1 -1
  8. package/lib/__lib__/QueryBuilderSetting.js.map +1 -1
  9. package/lib/__lib__/QueryBuilderTesting.js +1 -1
  10. package/lib/__lib__/QueryBuilderTesting.js.map +1 -1
  11. package/lib/components/QueryBuilderComponentElement.js +1 -1
  12. package/lib/components/QueryBuilderComponentElement.js.map +1 -1
  13. package/lib/components/QueryBuilderResultPanel.d.ts.map +1 -1
  14. package/lib/components/QueryBuilderResultPanel.js +2 -2
  15. package/lib/components/QueryBuilderResultPanel.js.map +1 -1
  16. package/lib/components/QueryBuilder_LegendApplicationPlugin.js +1 -2
  17. package/lib/components/QueryBuilder_LegendApplicationPlugin.js.map +1 -1
  18. package/lib/components/explorer/QueryBuilderExplorerPanel.d.ts.map +1 -1
  19. package/lib/components/explorer/QueryBuilderExplorerPanel.js +3 -3
  20. package/lib/components/explorer/QueryBuilderExplorerPanel.js.map +1 -1
  21. package/lib/components/fetch-structure/QueryBuilderFetchStructurePanel.d.ts.map +1 -1
  22. package/lib/components/fetch-structure/QueryBuilderFetchStructurePanel.js +3 -3
  23. package/lib/components/fetch-structure/QueryBuilderFetchStructurePanel.js.map +1 -1
  24. package/lib/components/fetch-structure/QueryBuilderPostFilterPanel.d.ts.map +1 -1
  25. package/lib/components/fetch-structure/QueryBuilderPostFilterPanel.js +60 -21
  26. package/lib/components/fetch-structure/QueryBuilderPostFilterPanel.js.map +1 -1
  27. package/lib/components/fetch-structure/QueryBuilderTDSPanel.d.ts.map +1 -1
  28. package/lib/components/fetch-structure/QueryBuilderTDSPanel.js +10 -2
  29. package/lib/components/fetch-structure/QueryBuilderTDSPanel.js.map +1 -1
  30. package/lib/components/fetch-structure/QueryBuilderTDSWindowPanel.d.ts.map +1 -1
  31. package/lib/components/fetch-structure/QueryBuilderTDSWindowPanel.js +2 -2
  32. package/lib/components/fetch-structure/QueryBuilderTDSWindowPanel.js.map +1 -1
  33. package/lib/components/filter/QueryBuilderFilterPanel.d.ts +4 -0
  34. package/lib/components/filter/QueryBuilderFilterPanel.d.ts.map +1 -1
  35. package/lib/components/filter/QueryBuilderFilterPanel.js +69 -31
  36. package/lib/components/filter/QueryBuilderFilterPanel.js.map +1 -1
  37. package/lib/components/shared/CustomDatePicker.js +1 -1
  38. package/lib/components/shared/CustomDatePicker.js.map +1 -1
  39. package/lib/graph/QueryBuilderMetaModelConst.js +3 -3
  40. package/lib/graph/QueryBuilderMetaModelConst.js.map +1 -1
  41. package/lib/graph-manager/QueryBuilderConst.js +1 -1
  42. package/lib/graph-manager/QueryBuilderConst.js.map +1 -1
  43. package/lib/graph-manager/protocol/pure/v1/V1_QueryBuilder_PureGraphManagerExtension.d.ts.map +1 -1
  44. package/lib/graph-manager/protocol/pure/v1/V1_QueryBuilder_PureGraphManagerExtension.js +4 -4
  45. package/lib/graph-manager/protocol/pure/v1/V1_QueryBuilder_PureGraphManagerExtension.js.map +1 -1
  46. package/lib/index.css +2 -2
  47. package/lib/index.css.map +1 -1
  48. package/lib/package.json +5 -5
  49. package/lib/stores/QueryBuilderChangeDetectionState.js +1 -1
  50. package/lib/stores/QueryBuilderChangeDetectionState.js.map +1 -1
  51. package/lib/stores/QueryBuilderCommand.js +1 -1
  52. package/lib/stores/QueryBuilderCommand.js.map +1 -1
  53. package/lib/stores/QueryBuilderConfig.js +2 -2
  54. package/lib/stores/QueryBuilderConfig.js.map +1 -1
  55. package/lib/stores/QueryBuilderGroupOperationHelper.js +1 -1
  56. package/lib/stores/QueryBuilderGroupOperationHelper.js.map +1 -1
  57. package/lib/stores/QueryBuilderResultState.d.ts +1 -0
  58. package/lib/stores/QueryBuilderResultState.d.ts.map +1 -1
  59. package/lib/stores/QueryBuilderResultState.js +1 -1
  60. package/lib/stores/QueryBuilderResultState.js.map +1 -1
  61. package/lib/stores/QueryBuilderStateHashUtils.js +1 -1
  62. package/lib/stores/QueryBuilderStateHashUtils.js.map +1 -1
  63. package/lib/stores/QueryBuilderTextEditorState.js +1 -1
  64. package/lib/stores/QueryBuilderTextEditorState.js.map +1 -1
  65. package/lib/stores/execution-plan/ExecutionPlanState.js +1 -1
  66. package/lib/stores/execution-plan/ExecutionPlanState.js.map +1 -1
  67. package/lib/stores/explorer/QueryBuilderExplorerState.js +1 -1
  68. package/lib/stores/explorer/QueryBuilderExplorerState.js.map +1 -1
  69. package/lib/stores/fetch-structure/QueryBuilderFetchStructureImplementationState.js +1 -1
  70. package/lib/stores/fetch-structure/QueryBuilderFetchStructureImplementationState.js.map +1 -1
  71. package/lib/stores/fetch-structure/graph-fetch/QueryBuilderGraphFetchTreeState.js +2 -2
  72. package/lib/stores/fetch-structure/graph-fetch/QueryBuilderGraphFetchTreeState.js.map +1 -1
  73. package/lib/stores/fetch-structure/tds/QueryBuilderTDSState.js +1 -1
  74. package/lib/stores/fetch-structure/tds/QueryBuilderTDSState.js.map +1 -1
  75. package/lib/stores/fetch-structure/tds/QueryResultSetModifierState.js +1 -1
  76. package/lib/stores/fetch-structure/tds/QueryResultSetModifierState.js.map +1 -1
  77. package/lib/stores/fetch-structure/tds/post-filter/QueryBuilderPostFilterState.js +2 -2
  78. package/lib/stores/fetch-structure/tds/post-filter/QueryBuilderPostFilterState.js.map +1 -1
  79. package/lib/stores/filter/QueryBuilderFilterState.js +1 -1
  80. package/lib/stores/filter/QueryBuilderFilterState.js.map +1 -1
  81. package/lib/stores/shared/LambdaParameterState.js +1 -1
  82. package/lib/stores/shared/LambdaParameterState.js.map +1 -1
  83. package/package.json +13 -13
  84. package/src/components/QueryBuilderResultPanel.tsx +1 -2
  85. package/src/components/explorer/QueryBuilderExplorerPanel.tsx +10 -14
  86. package/src/components/fetch-structure/QueryBuilderFetchStructurePanel.tsx +6 -4
  87. package/src/components/fetch-structure/QueryBuilderPostFilterPanel.tsx +103 -14
  88. package/src/components/fetch-structure/QueryBuilderTDSPanel.tsx +18 -1
  89. package/src/components/fetch-structure/QueryBuilderTDSWindowPanel.tsx +12 -10
  90. package/src/components/filter/QueryBuilderFilterPanel.tsx +134 -42
  91. package/src/graph-manager/protocol/pure/v1/V1_QueryBuilder_PureGraphManagerExtension.ts +4 -5
  92. package/src/stores/QueryBuilderResultState.ts +1 -1
@@ -48,7 +48,12 @@ import {
48
48
  buildPropertyExpressionFromExplorerTreeNodeData,
49
49
  QUERY_BUILDER_EXPLORER_TREE_DND_TYPE,
50
50
  } from '../../stores/explorer/QueryBuilderExplorerState.js';
51
- import { type DropTargetMonitor, useDrag, useDrop } from 'react-dnd';
51
+ import {
52
+ type DropTargetMonitor,
53
+ useDrag,
54
+ useDrop,
55
+ useDragLayer,
56
+ } from 'react-dnd';
52
57
  import {
53
58
  type QueryBuilderProjectionColumnDragSource,
54
59
  type QueryBuilderProjectionColumnState,
@@ -932,6 +937,16 @@ export const QueryBuilderTDSPanel = observer(
932
937
  [handleDrop],
933
938
  );
934
939
 
940
+ const { showDroppableSuggestion } = useDragLayer((monitor) => ({
941
+ showDroppableSuggestion:
942
+ monitor.isDragging() &&
943
+ [
944
+ QUERY_BUILDER_EXPLORER_TREE_DND_TYPE.ENUM_PROPERTY,
945
+ QUERY_BUILDER_EXPLORER_TREE_DND_TYPE.PRIMITIVE_PROPERTY,
946
+ QUERY_BUILDER_FUNCTION_DND_TYPE,
947
+ ].includes(monitor.getItemType()?.toString() ?? ''),
948
+ }));
949
+
935
950
  useEffect(() => {
936
951
  flowResult(tdsState.convertDerivationProjectionObjects()).catch(
937
952
  applicationStore.alertUnhandledError,
@@ -974,6 +989,8 @@ export const QueryBuilderTDSPanel = observer(
974
989
  <div className="query-builder__projection__content">
975
990
  <PanelDropZone
976
991
  isDragOver={isDragOver}
992
+ showDroppableSuggestion={showDroppableSuggestion}
993
+ className="query-builder__panel--droppable"
977
994
  dropTargetConnector={dropTargetConnector}
978
995
  >
979
996
  {!projectionColumns.length && (
@@ -44,6 +44,10 @@ import {
44
44
  ModalFooterButton,
45
45
  PanelDnDEntryDragHandle,
46
46
  PanelDnDEntry,
47
+ PanelHeaderActionItem,
48
+ PanelHeader,
49
+ PanelHeaderActions,
50
+ Panel,
47
51
  } from '@finos/legend-art';
48
52
  import { assertErrorThrown, guaranteeNonNullable } from '@finos/legend-shared';
49
53
  import { observer } from 'mobx-react-lite';
@@ -1175,12 +1179,12 @@ export const QueryBuilderTDSWindowPanel = observer(
1175
1179
  [applicationStore, handleDrop],
1176
1180
  );
1177
1181
  return (
1178
- <div className="panel">
1182
+ <Panel>
1179
1183
  <div
1180
1184
  data-testid={QUERY_BUILDER_TEST_ID.QUERY_BUILDER_WINDOW_GROUPBY}
1181
1185
  className="panel"
1182
1186
  >
1183
- <div className="panel__header">
1187
+ <PanelHeader>
1184
1188
  <div className="panel__header__title">
1185
1189
  <div className="panel__header__title__label">Window Function</div>
1186
1190
  {tdsWindowState.windowValidationIssues.length && (
@@ -1189,18 +1193,16 @@ export const QueryBuilderTDSWindowPanel = observer(
1189
1193
  />
1190
1194
  )}
1191
1195
  </div>
1192
- <div className="panel__header__actions">
1193
- <button
1194
- className="panel__header__action"
1196
+ <PanelHeaderActions>
1197
+ <PanelHeaderActionItem
1195
1198
  onClick={createTDSWindow}
1196
1199
  disabled={!tdsWindowState.tdsState.tdsColumns.length}
1197
- tabIndex={-1}
1198
1200
  title="Create Window Function Column"
1199
1201
  >
1200
1202
  <PlusIcon />
1201
- </button>
1202
- </div>
1203
- </div>
1203
+ </PanelHeaderActionItem>
1204
+ </PanelHeaderActions>
1205
+ </PanelHeader>
1204
1206
  <PanelContent>
1205
1207
  <PanelDropZone
1206
1208
  isDragOver={isDragOver}
@@ -1234,7 +1236,7 @@ export const QueryBuilderTDSWindowPanel = observer(
1234
1236
  />
1235
1237
  )}
1236
1238
  </div>
1237
- </div>
1239
+ </Panel>
1238
1240
  );
1239
1241
  },
1240
1242
  );
@@ -56,7 +56,7 @@ import {
56
56
  QueryBuilderFilterTreeBlankConditionNodeData,
57
57
  QueryBuilderFilterTreeGroupNodeData,
58
58
  } from '../../stores/filter/QueryBuilderFilterState.js';
59
- import { useDrag, useDrop } from 'react-dnd';
59
+ import { useDrag, useDragLayer, useDrop } from 'react-dnd';
60
60
  import {
61
61
  type QueryBuilderExplorerTreeDragSource,
62
62
  type QueryBuilderExplorerTreePropertyNodeData,
@@ -88,12 +88,26 @@ import {
88
88
  } from '../shared/BasicValueSpecificationEditor.js';
89
89
  import { QueryBuilderTelemetryHelper } from '../../__lib__/QueryBuilderTelemetryHelper.js';
90
90
 
91
+ export const IS_DRAGGABLE_FILTER_DND_TYPES_FETCH_SUPPORTED = [
92
+ QUERY_BUILDER_FILTER_DND_TYPE.CONDITION,
93
+ QUERY_BUILDER_EXPLORER_TREE_DND_TYPE.ENUM_PROPERTY,
94
+ QUERY_BUILDER_EXPLORER_TREE_DND_TYPE.PRIMITIVE_PROPERTY,
95
+ QUERY_BUILDER_PROJECTION_COLUMN_DND_TYPE,
96
+ ];
97
+
98
+ export const IS_DRAGGABLE_FILTER_DND_TYPES = [
99
+ QUERY_BUILDER_FILTER_DND_TYPE.CONDITION,
100
+ QUERY_BUILDER_EXPLORER_TREE_DND_TYPE.ENUM_PROPERTY,
101
+ QUERY_BUILDER_EXPLORER_TREE_DND_TYPE.PRIMITIVE_PROPERTY,
102
+ ];
103
+
91
104
  const QueryBuilderFilterGroupConditionEditor = observer(
92
105
  (props: {
93
106
  node: QueryBuilderFilterTreeGroupNodeData;
94
107
  isDragOver: boolean;
108
+ showDroppableSuggestion: boolean;
95
109
  }) => {
96
- const { node, isDragOver } = props;
110
+ const { node, isDragOver, showDroppableSuggestion } = props;
97
111
  const switchOperation: React.MouseEventHandler<HTMLDivElement> = (
98
112
  event,
99
113
  ): void => {
@@ -105,30 +119,31 @@ const QueryBuilderFilterGroupConditionEditor = observer(
105
119
  );
106
120
  };
107
121
  return (
108
- <div className="query-builder-filter-tree__node__label__content">
109
- <PanelEntryDropZonePlaceholder
110
- showPlaceholder={isDragOver}
111
- label="Add to Logical Group"
112
- className="query-builder__dnd__placeholder"
113
- >
122
+ <div className="query-builder-filter-tree__node__label__content dnd__entry__container">
123
+ {showDroppableSuggestion && (
114
124
  <div
115
- className={clsx('query-builder-filter-tree__group-node', {
116
- 'query-builder-filter-tree__group-node--and':
117
- node.groupOperation === QUERY_BUILDER_GROUP_OPERATION.AND,
118
- 'query-builder-filter-tree__group-node--or':
119
- node.groupOperation === QUERY_BUILDER_GROUP_OPERATION.OR,
125
+ className={clsx('dnd__entry--droppable__indicator ', {
126
+ 'dnd__entry--droppable__indicator--dragover': isDragOver,
120
127
  })}
121
- title="Switch Operation"
122
- onClick={switchOperation}
123
- >
124
- <div className="query-builder-filter-tree__group-node__label">
125
- {node.groupOperation}
126
- </div>
127
- <button className="query-builder-filter-tree__group-node__action">
128
- <FilledTriangleIcon />
129
- </button>
128
+ ></div>
129
+ )}
130
+ <div
131
+ className={clsx('query-builder-filter-tree__group-node', {
132
+ 'query-builder-filter-tree__group-node--and':
133
+ node.groupOperation === QUERY_BUILDER_GROUP_OPERATION.AND,
134
+ 'query-builder-filter-tree__group-node--or':
135
+ node.groupOperation === QUERY_BUILDER_GROUP_OPERATION.OR,
136
+ })}
137
+ title="Switch Operation"
138
+ onClick={switchOperation}
139
+ >
140
+ <div className="query-builder-filter-tree__group-node__label">
141
+ {node.groupOperation}
130
142
  </div>
131
- </PanelEntryDropZonePlaceholder>
143
+ <button className="query-builder-filter-tree__group-node__action">
144
+ <FilledTriangleIcon />
145
+ </button>
146
+ </div>
132
147
  </div>
133
148
  );
134
149
  },
@@ -190,6 +205,7 @@ const QueryBuilderFilterConditionEditor = observer(
190
205
  }),
191
206
  [handleDrop],
192
207
  );
208
+
193
209
  const resetNode = (): void => {
194
210
  node.condition.setValue(
195
211
  node.condition.operator.getDefaultFilterConditionValue(node.condition),
@@ -215,8 +231,29 @@ const QueryBuilderFilterConditionEditor = observer(
215
231
  reloadValues: debouncedTypeaheadSearch,
216
232
  cleanUpReloadValues,
217
233
  };
234
+
235
+ const { showDroppableSuggestion } = useDragLayer((monitor) => ({
236
+ showDroppableSuggestion:
237
+ monitor.isDragging() &&
238
+ (queryBuilderState.TEMPORARY__isDnDFetchStructureToFilterSupported
239
+ ? IS_DRAGGABLE_FILTER_DND_TYPES_FETCH_SUPPORTED
240
+ : IS_DRAGGABLE_FILTER_DND_TYPES
241
+ ).includes(monitor.getItemType()?.toString() ?? ''),
242
+ }));
243
+
218
244
  return (
219
- <div className="query-builder-filter-tree__node__label__content">
245
+ <div className="query-builder-filter-tree__node__label__content dnd__entry__container">
246
+ {showDroppableSuggestion && (
247
+ <div
248
+ className={clsx(
249
+ 'dnd__entry--droppable__indicator dnd__entry-potential__oiodropzone__indicator--full',
250
+ {
251
+ 'dnd__entry--droppable__indicator--dragover': isDragOver,
252
+ },
253
+ )}
254
+ ></div>
255
+ )}
256
+
220
257
  <PanelEntryDropZonePlaceholder
221
258
  showPlaceholder={isDragOver}
222
259
  label="Add New Logical Group"
@@ -299,8 +336,9 @@ const QueryBuilderFilterBlankConditionEditor = observer(
299
336
  (props: {
300
337
  node: QueryBuilderFilterTreeBlankConditionNodeData;
301
338
  isDragOver: boolean;
339
+ showDroppableSuggestion: boolean;
302
340
  }) => {
303
- const { isDragOver } = props;
341
+ const { isDragOver, showDroppableSuggestion } = props;
304
342
  return (
305
343
  <div className="query-builder-filter-tree__node__label__content">
306
344
  <PanelEntryDropZonePlaceholder
@@ -308,6 +346,9 @@ const QueryBuilderFilterBlankConditionEditor = observer(
308
346
  label="Create Condition"
309
347
  className="query-builder__dnd__placeholder"
310
348
  >
349
+ {showDroppableSuggestion && (
350
+ <div className="query-builder-filter-tree__blank-node--droppable"></div>
351
+ )}
311
352
  <div className="query-builder-filter-tree__blank-node">blank</div>
312
353
  </PanelEntryDropZonePlaceholder>
313
354
  </div>
@@ -390,11 +431,31 @@ const QueryBuilderFilterTreeNodeContainer = observer(
390
431
  // Drag and Drop
391
432
  const handleDrop = useCallback(
392
433
  (item: QueryBuilderFilterDropTarget, type: string): void => {
393
- if (
394
- Object.values<string>(QUERY_BUILDER_FILTER_DND_TYPE).includes(type)
395
- ) {
396
- // const dropNode = (item as QueryBuilderFilterConditionDragSource).node;
397
- // TODO: re-arrange
434
+ if (QUERY_BUILDER_FILTER_DND_TYPE.CONDITION === type) {
435
+ const nodeBeingDragged = (
436
+ item as QueryBuilderFilterConditionDragSource
437
+ ).node;
438
+
439
+ const newCreatedNode = new QueryBuilderFilterTreeConditionNodeData(
440
+ undefined,
441
+ (
442
+ filterState.nodes.get(
443
+ nodeBeingDragged.id,
444
+ ) as QueryBuilderFilterTreeConditionNodeData
445
+ ).condition,
446
+ );
447
+
448
+ if (node instanceof QueryBuilderFilterTreeBlankConditionNodeData) {
449
+ filterState.replaceBlankNodeWithNode(newCreatedNode, node);
450
+ filterState.removeNodeAndPruneBranch(nodeBeingDragged);
451
+ } else if (node instanceof QueryBuilderFilterTreeConditionNodeData) {
452
+ filterState.newGroupWithConditionFromNode(newCreatedNode, node);
453
+
454
+ filterState.removeNodeAndPruneBranch(nodeBeingDragged);
455
+ } else if (node instanceof QueryBuilderFilterTreeGroupNodeData) {
456
+ filterState.addNodeFromNode(newCreatedNode, node);
457
+ filterState.removeNodeAndPruneBranch(nodeBeingDragged);
458
+ }
398
459
  } else {
399
460
  let filterConditionState: FilterConditionState;
400
461
  try {
@@ -469,17 +530,8 @@ const QueryBuilderFilterTreeNodeContainer = observer(
469
530
  () => ({
470
531
  accept:
471
532
  queryBuilderState.TEMPORARY__isDnDFetchStructureToFilterSupported
472
- ? [
473
- ...Object.values(QUERY_BUILDER_FILTER_DND_TYPE),
474
- QUERY_BUILDER_EXPLORER_TREE_DND_TYPE.ENUM_PROPERTY,
475
- QUERY_BUILDER_EXPLORER_TREE_DND_TYPE.PRIMITIVE_PROPERTY,
476
- QUERY_BUILDER_PROJECTION_COLUMN_DND_TYPE,
477
- ]
478
- : [
479
- ...Object.values(QUERY_BUILDER_FILTER_DND_TYPE),
480
- QUERY_BUILDER_EXPLORER_TREE_DND_TYPE.ENUM_PROPERTY,
481
- QUERY_BUILDER_EXPLORER_TREE_DND_TYPE.PRIMITIVE_PROPERTY,
482
- ],
533
+ ? IS_DRAGGABLE_FILTER_DND_TYPES_FETCH_SUPPORTED
534
+ : IS_DRAGGABLE_FILTER_DND_TYPES,
483
535
  drop: (item, monitor): void => {
484
536
  if (!monitor.didDrop()) {
485
537
  handleDrop(item, monitor.getItemType() as string);
@@ -508,6 +560,15 @@ const QueryBuilderFilterTreeNodeContainer = observer(
508
560
  dragConnector(dropConnector(ref));
509
561
  useDragPreviewLayer(dragPreviewConnector);
510
562
 
563
+ const { showDroppableSuggestion } = useDragLayer((monitor) => ({
564
+ showDroppableSuggestion:
565
+ monitor.isDragging() &&
566
+ (queryBuilderState.TEMPORARY__isDnDFetchStructureToFilterSupported
567
+ ? IS_DRAGGABLE_FILTER_DND_TYPES_FETCH_SUPPORTED
568
+ : IS_DRAGGABLE_FILTER_DND_TYPES
569
+ ).includes(monitor.getItemType()?.toString() ?? ''),
570
+ }));
571
+
511
572
  // context menu
512
573
  const onContextMenuOpen = (): void => setIsSelectedFromContextMenu(true);
513
574
  const onContextMenuClose = (): void => setIsSelectedFromContextMenu(false);
@@ -566,6 +627,7 @@ const QueryBuilderFilterTreeNodeContainer = observer(
566
627
  {node instanceof QueryBuilderFilterTreeGroupNodeData && (
567
628
  <QueryBuilderFilterGroupConditionEditor
568
629
  node={node}
630
+ showDroppableSuggestion={showDroppableSuggestion}
569
631
  isDragOver={isDragOver}
570
632
  />
571
633
  )}
@@ -579,6 +641,7 @@ const QueryBuilderFilterTreeNodeContainer = observer(
579
641
  <QueryBuilderFilterBlankConditionEditor
580
642
  node={node}
581
643
  isDragOver={isDragOver}
644
+ showDroppableSuggestion={showDroppableSuggestion}
582
645
  />
583
646
  )}
584
647
  </div>
@@ -747,6 +810,16 @@ export const QueryBuilderFilterPanel = observer(
747
810
  );
748
811
  }
749
812
  };
813
+
814
+ const { showDroppableSuggestion } = useDragLayer((monitor) => ({
815
+ showDroppableSuggestion:
816
+ monitor.isDragging() &&
817
+ (queryBuilderState.TEMPORARY__isDnDFetchStructureToFilterSupported
818
+ ? IS_DRAGGABLE_FILTER_DND_TYPES_FETCH_SUPPORTED
819
+ : IS_DRAGGABLE_FILTER_DND_TYPES
820
+ ).includes(monitor.getItemType()?.toString() ?? ''),
821
+ }));
822
+
750
823
  // Drag and Drop
751
824
  const handleDrop = useCallback(
752
825
  (item: QueryBuilderFilterDropTarget, type: string): void => {
@@ -795,6 +868,7 @@ export const QueryBuilderFilterPanel = observer(
795
868
  },
796
869
  [applicationStore, filterState],
797
870
  );
871
+
798
872
  const [{ isDragOver }, dropTargetConnector] = useDrop<
799
873
  QueryBuilderExplorerTreeDragSource,
800
874
  void,
@@ -913,7 +987,11 @@ export const QueryBuilderFilterPanel = observer(
913
987
  </div>
914
988
  <PanelContent>
915
989
  <PanelDropZone
916
- isDragOver={isDragOver}
990
+ isDragOver={isDragOver && filterState.isEmpty}
991
+ showDroppableSuggestion={
992
+ showDroppableSuggestion && filterState.isEmpty
993
+ }
994
+ className="query-builder__panel--droppable"
917
995
  dropTargetConnector={dropTargetConnector}
918
996
  >
919
997
  {filterState.isEmpty && (
@@ -933,6 +1011,20 @@ export const QueryBuilderFilterPanel = observer(
933
1011
  <QueryBuilderFilterTree queryBuilderState={queryBuilderState} />
934
1012
  </>
935
1013
  )}
1014
+
1015
+ {showDroppableSuggestion && !filterState.isEmpty && (
1016
+ <div
1017
+ ref={dropTargetConnector}
1018
+ className={clsx(
1019
+ 'query-builder-post-filter-tree__blank-node--droppable--tall',
1020
+ {
1021
+ 'dnd__entry--droppable__indicator--dragover': isDragOver,
1022
+ },
1023
+ )}
1024
+ >
1025
+ Add filter to main group
1026
+ </div>
1027
+ )}
936
1028
  </PanelDropZone>
937
1029
  </PanelContent>
938
1030
  </div>
@@ -25,7 +25,6 @@ import {
25
25
  V1_PureMultiExecution,
26
26
  V1_Service,
27
27
  V1_PackageableRuntime,
28
- type V1_PackageableElement,
29
28
  type PureModel,
30
29
  V1_PureGraphManager,
31
30
  PureClientVersion,
@@ -72,10 +71,10 @@ export class V1_QueryBuilder_PureGraphManagerExtension extends QueryBuilder_Pure
72
71
  entities,
73
72
  dependencyEntitiesIndex,
74
73
  (entity: Entity): boolean =>
75
- ((entity.content as PlainObject<V1_PackageableElement>)
76
- ._type as string) === V1_MAPPING_ELEMENT_PROTOCOL_TYPE ||
77
- ((entity.content as PlainObject<V1_PackageableElement>)
78
- ._type as string) === V1_PACKAGEABLE_RUNTIME_ELEMENT_PROTOCOL_TYPE,
74
+ (entity.content._type as string) ===
75
+ V1_MAPPING_ELEMENT_PROTOCOL_TYPE ||
76
+ (entity.content._type as string) ===
77
+ V1_PACKAGEABLE_RUNTIME_ELEMENT_PROTOCOL_TYPE,
79
78
  );
80
79
  // handle mapping includes
81
80
  const mappings = [
@@ -49,7 +49,7 @@ import { QueryBuilderTelemetryHelper } from '../__lib__/QueryBuilderTelemetryHel
49
49
  import { QUERY_BUILDER_EVENT } from '../__lib__/QueryBuilderEvent.js';
50
50
  import { ExecutionPlanState } from './execution-plan/ExecutionPlanState.js';
51
51
 
52
- const DEFAULT_LIMIT = 1000;
52
+ export const DEFAULT_LIMIT = 1000;
53
53
 
54
54
  export interface ExportDataInfo {
55
55
  contentType: ContentType;