@finos/legend-query-builder 4.0.8 → 4.0.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (101) 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 +210 -69
  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 +17 -1
  47. package/lib/index.css.map +1 -1
  48. package/lib/package.json +7 -7
  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 +19 -0
  58. package/lib/stores/QueryBuilderResultState.d.ts.map +1 -1
  59. package/lib/stores/QueryBuilderResultState.js +48 -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.d.ts.map +1 -1
  78. package/lib/stores/fetch-structure/tds/post-filter/QueryBuilderPostFilterState.js +2 -2
  79. package/lib/stores/fetch-structure/tds/post-filter/QueryBuilderPostFilterState.js.map +1 -1
  80. package/lib/stores/filter/QueryBuilderFilterState.js +1 -1
  81. package/lib/stores/filter/QueryBuilderFilterState.js.map +1 -1
  82. package/lib/stores/shared/LambdaParameterState.d.ts.map +1 -1
  83. package/lib/stores/shared/LambdaParameterState.js +2 -2
  84. package/lib/stores/shared/LambdaParameterState.js.map +1 -1
  85. package/lib/stores/shared/ValueSpecificationEditorHelper.d.ts +5 -2
  86. package/lib/stores/shared/ValueSpecificationEditorHelper.d.ts.map +1 -1
  87. package/lib/stores/shared/ValueSpecificationEditorHelper.js +30 -40
  88. package/lib/stores/shared/ValueSpecificationEditorHelper.js.map +1 -1
  89. package/package.json +15 -15
  90. package/src/components/QueryBuilderResultPanel.tsx +358 -93
  91. package/src/components/explorer/QueryBuilderExplorerPanel.tsx +10 -14
  92. package/src/components/fetch-structure/QueryBuilderFetchStructurePanel.tsx +6 -4
  93. package/src/components/fetch-structure/QueryBuilderPostFilterPanel.tsx +103 -14
  94. package/src/components/fetch-structure/QueryBuilderTDSPanel.tsx +18 -1
  95. package/src/components/fetch-structure/QueryBuilderTDSWindowPanel.tsx +12 -10
  96. package/src/components/filter/QueryBuilderFilterPanel.tsx +134 -42
  97. package/src/graph-manager/protocol/pure/v1/V1_QueryBuilder_PureGraphManagerExtension.ts +4 -5
  98. package/src/stores/QueryBuilderResultState.ts +82 -0
  99. package/src/stores/fetch-structure/tds/post-filter/QueryBuilderPostFilterState.ts +1 -0
  100. package/src/stores/shared/LambdaParameterState.ts +1 -0
  101. package/src/stores/shared/ValueSpecificationEditorHelper.ts +80 -57
@@ -53,6 +53,9 @@ import {
53
53
  ModalFooter,
54
54
  ModalHeader,
55
55
  ModalFooterButton,
56
+ PanelHeaderActionItem,
57
+ PanelHeaderActions,
58
+ PanelHeader,
56
59
  } from '@finos/legend-art';
57
60
  import {
58
61
  type QueryBuilderExplorerTreeDragSource,
@@ -854,11 +857,8 @@ export const QueryBuilderExplorerPanel = observer(
854
857
  backdrop__element: applicationStore.layoutService.showBackdrop,
855
858
  })}
856
859
  >
857
- <div className="panel__header">
858
- <div className="panel__header__title">
859
- <div className="panel__header__title__label">explorer</div>
860
- </div>
861
- <div className="panel__header__actions">
860
+ <PanelHeader title="explorer">
861
+ <PanelHeaderActions>
862
862
  <button
863
863
  ref={searchButtonRef}
864
864
  className={clsx('panel__header__action', {
@@ -871,14 +871,9 @@ export const QueryBuilderExplorerPanel = observer(
871
871
  >
872
872
  <SearchIcon />
873
873
  </button>
874
- <button
875
- className="panel__header__action"
876
- onClick={collapseTree}
877
- tabIndex={-1}
878
- title="Collapse Tree"
879
- >
874
+ <PanelHeaderActionItem onClick={collapseTree} title="Collapse Tree">
880
875
  <CompressIcon />
881
- </button>
876
+ </PanelHeaderActionItem>
882
877
  <DropdownMenu
883
878
  className="panel__header__action"
884
879
  title="Show Options Menu..."
@@ -924,14 +919,15 @@ export const QueryBuilderExplorerPanel = observer(
924
919
  >
925
920
  <MoreVerticalIcon className="query-builder__icon__more-options" />
926
921
  </DropdownMenu>
927
- </div>
922
+ </PanelHeaderActions>
928
923
  {propertySearchPanelState.isSearchPanelOpen && (
929
924
  <QueryBuilderPropertySearchPanel
930
925
  queryBuilderState={queryBuilderState}
931
926
  triggerElement={searchButtonRef.current}
932
927
  />
933
928
  )}
934
- </div>
929
+ </PanelHeader>
930
+
935
931
  <div className="panel__content query-builder-explorer-tree__content">
936
932
  <PanelLoadingIndicator
937
933
  isLoading={
@@ -20,6 +20,8 @@ import {
20
20
  BlankPanelContent,
21
21
  Panel,
22
22
  PanelContent,
23
+ PanelHeader,
24
+ PanelHeaderActions,
23
25
  } from '@finos/legend-art';
24
26
  import type { QueryBuilderState } from '../../stores/QueryBuilderState.js';
25
27
  import { prettyCONSTName } from '@finos/legend-shared';
@@ -80,7 +82,7 @@ export const QueryBuilderFetchStructurePanel = observer(
80
82
 
81
83
  return (
82
84
  <Panel>
83
- <div className="panel__header">
85
+ <PanelHeader>
84
86
  <div className="panel__header__title">
85
87
  <div className="panel__header__title__label">fetch structure</div>
86
88
  {fetchStructureState.implementation.fetchStructureValidationIssues
@@ -93,7 +95,7 @@ export const QueryBuilderFetchStructurePanel = observer(
93
95
  />
94
96
  )}
95
97
  </div>
96
- <div className="panel__header__actions">
98
+ <PanelHeaderActions>
97
99
  <div className="query-builder__fetch__structure__modes">
98
100
  {Object.values(FETCH_STRUCTURE_IMPLEMENTATION).map((type) => (
99
101
  <button
@@ -108,8 +110,8 @@ export const QueryBuilderFetchStructurePanel = observer(
108
110
  </button>
109
111
  ))}
110
112
  </div>
111
- </div>
112
- </div>
113
+ </PanelHeaderActions>
114
+ </PanelHeader>
113
115
  <QueryBuilderFetchStructureEditor
114
116
  queryBuilderState={queryBuilderState}
115
117
  />
@@ -61,7 +61,7 @@ import {
61
61
  import { flowResult } from 'mobx';
62
62
  import { observer } from 'mobx-react-lite';
63
63
  import { forwardRef, useCallback, useMemo, useRef, useState } from 'react';
64
- import { useDrop, useDrag } from 'react-dnd';
64
+ import { useDrop, useDrag, useDragLayer } from 'react-dnd';
65
65
  import { QueryBuilderAggregateColumnState } from '../../stores/fetch-structure/tds/aggregation/QueryBuilderAggregationState.js';
66
66
  import type { QueryBuilderPostFilterOperator } from '../../stores/fetch-structure/tds/post-filter/QueryBuilderPostFilterOperator.js';
67
67
  import {
@@ -71,8 +71,8 @@ import {
71
71
  type QueryBuilderPostFilterConditionDragSource,
72
72
  QueryBuilderPostFilterTreeConditionNodeData,
73
73
  QueryBuilderPostFilterTreeGroupNodeData,
74
- QUERY_BUILDER_POST_FILTER_DND_TYPE,
75
74
  QueryBuilderPostFilterTreeBlankConditionNodeData,
75
+ QUERY_BUILDER_POST_FILTER_DND_TYPE,
76
76
  } from '../../stores/fetch-structure/tds/post-filter/QueryBuilderPostFilterState.js';
77
77
  import {
78
78
  type QueryBuilderProjectionColumnState,
@@ -153,8 +153,9 @@ const QueryBuilderPostFilterGroupConditionEditor = observer(
153
153
  (props: {
154
154
  node: QueryBuilderPostFilterTreeGroupNodeData;
155
155
  isDragOver: boolean;
156
+ showDroppableSuggestion: boolean;
156
157
  }) => {
157
- const { node, isDragOver } = props;
158
+ const { node, isDragOver, showDroppableSuggestion } = props;
158
159
  const switchOperation: React.MouseEventHandler<HTMLDivElement> = (
159
160
  event,
160
161
  ): void => {
@@ -166,7 +167,14 @@ const QueryBuilderPostFilterGroupConditionEditor = observer(
166
167
  );
167
168
  };
168
169
  return (
169
- <div className="query-builder-post-filter-tree__node__label__content">
170
+ <div className="query-builder-post-filter-tree__node__label__content dnd__entry__container">
171
+ {showDroppableSuggestion && (
172
+ <div
173
+ className={clsx('dnd__entry--droppable__indicator ', {
174
+ 'dnd__entry--droppable__indicator--dragover': isDragOver,
175
+ })}
176
+ ></div>
177
+ )}
170
178
  <PanelEntryDropZonePlaceholder
171
179
  showPlaceholder={isDragOver}
172
180
  label="Add to Logical Group"
@@ -359,8 +367,25 @@ const QueryBuilderPostFilterConditionEditor = observer(
359
367
  cleanUpReloadValues,
360
368
  };
361
369
 
370
+ const { showDroppableSuggestion } = useDragLayer((monitor) => ({
371
+ showDroppableSuggestion:
372
+ monitor.isDragging() &&
373
+ (monitor.getItemType() === QUERY_BUILDER_PROJECTION_COLUMN_DND_TYPE ||
374
+ monitor.getItemType() === QUERY_BUILDER_WINDOW_COLUMN_DND_TYPE),
375
+ }));
376
+
362
377
  return (
363
- <div className="query-builder-post-filter-tree__node__label__content">
378
+ <div className="query-builder-post-filter-tree__node__label__content dnd__entry__container">
379
+ {showDroppableSuggestion && (
380
+ <div
381
+ className={clsx(
382
+ 'dnd__entry--droppable__indicator query-builder-post-filter-tree__droppable--full',
383
+ {
384
+ 'dnd__entry--droppable__indicator--dragover': isDragOver,
385
+ },
386
+ )}
387
+ ></div>
388
+ )}
364
389
  <PanelEntryDropZonePlaceholder
365
390
  showPlaceholder={isDragOver}
366
391
  label="Add New Logical Group"
@@ -442,8 +467,9 @@ const QueryBuilderPostFilterBlankConditionEditor = observer(
442
467
  (props: {
443
468
  node: QueryBuilderPostFilterTreeBlankConditionNodeData;
444
469
  isDragOver: boolean;
470
+ showDroppableSuggestion: boolean;
445
471
  }) => {
446
- const { isDragOver } = props;
472
+ const { isDragOver, showDroppableSuggestion } = props;
447
473
  return (
448
474
  <div className="query-builder-post-filter-tree__node__label__content">
449
475
  <PanelEntryDropZonePlaceholder
@@ -451,7 +477,12 @@ const QueryBuilderPostFilterBlankConditionEditor = observer(
451
477
  label="Create Condition"
452
478
  className="query-builder__dnd__placeholder"
453
479
  >
454
- <div className="query-builder-post-filter-tree__blank-node">
480
+ <div
481
+ className={clsx('query-builder-post-filter-tree__blank-node', {
482
+ 'query-builder-post-filter-tree__blank-node--droppable':
483
+ showDroppableSuggestion,
484
+ })}
485
+ >
455
486
  blank
456
487
  </div>
457
488
  </PanelEntryDropZonePlaceholder>
@@ -484,7 +515,34 @@ const QueryBuilderPostFilterTreeNodeContainer = observer(
484
515
  postFilterState.removeNodeAndPruneBranch(node);
485
516
  const handleDrop = useCallback(
486
517
  (item: QueryBuilderPostFilterDropTarget, type: string): void => {
487
- if (
518
+ if (QUERY_BUILDER_POST_FILTER_DND_TYPE.CONDITION === type) {
519
+ const nodeBeingDragged = (
520
+ item as QueryBuilderPostFilterConditionDragSource
521
+ ).node;
522
+
523
+ const newCreatedNode =
524
+ new QueryBuilderPostFilterTreeConditionNodeData(
525
+ undefined,
526
+ (
527
+ postFilterState.nodes.get(
528
+ nodeBeingDragged.id,
529
+ ) as QueryBuilderPostFilterTreeConditionNodeData
530
+ ).condition,
531
+ );
532
+
533
+ if (node instanceof QueryBuilderPostFilterTreeConditionNodeData) {
534
+ postFilterState.newGroupWithConditionFromNode(newCreatedNode, node);
535
+ postFilterState.removeNodeAndPruneBranch(nodeBeingDragged);
536
+ } else if (node instanceof QueryBuilderPostFilterTreeGroupNodeData) {
537
+ postFilterState.addNodeFromNode(newCreatedNode, node);
538
+ postFilterState.removeNodeAndPruneBranch(nodeBeingDragged);
539
+ } else if (
540
+ node instanceof QueryBuilderPostFilterTreeBlankConditionNodeData
541
+ ) {
542
+ postFilterState.replaceBlankNodeWithNode(newCreatedNode, node);
543
+ postFilterState.removeNodeAndPruneBranch(nodeBeingDragged);
544
+ }
545
+ } else if (
488
546
  type === QUERY_BUILDER_PROJECTION_COLUMN_DND_TYPE ||
489
547
  type === QUERY_BUILDER_WINDOW_COLUMN_DND_TYPE
490
548
  ) {
@@ -588,6 +646,13 @@ const QueryBuilderPostFilterTreeNodeContainer = observer(
588
646
  const onContextMenuOpen = (): void => setIsSelectedFromContextMenu(true);
589
647
  const onContextMenuClose = (): void => setIsSelectedFromContextMenu(false);
590
648
 
649
+ const { showDroppableSuggestion } = useDragLayer((monitor) => ({
650
+ showDroppableSuggestion:
651
+ monitor.isDragging() &&
652
+ (monitor.getItemType() === QUERY_BUILDER_PROJECTION_COLUMN_DND_TYPE ||
653
+ monitor.getItemType() === QUERY_BUILDER_WINDOW_COLUMN_DND_TYPE),
654
+ }));
655
+
591
656
  return (
592
657
  <ContextMenu
593
658
  content={
@@ -642,6 +707,7 @@ const QueryBuilderPostFilterTreeNodeContainer = observer(
642
707
  {node instanceof QueryBuilderPostFilterTreeGroupNodeData && (
643
708
  <QueryBuilderPostFilterGroupConditionEditor
644
709
  node={node}
710
+ showDroppableSuggestion={showDroppableSuggestion}
645
711
  isDragOver={isDragOver}
646
712
  />
647
713
  )}
@@ -656,6 +722,7 @@ const QueryBuilderPostFilterTreeNodeContainer = observer(
656
722
  <QueryBuilderPostFilterBlankConditionEditor
657
723
  node={node}
658
724
  isDragOver={isDragOver}
725
+ showDroppableSuggestion={showDroppableSuggestion}
659
726
  />
660
727
  )}
661
728
  </div>
@@ -892,11 +959,15 @@ const QueryBuilderPostFilterPanelContent = observer(
892
959
  [applicationStore, handleDrop],
893
960
  );
894
961
 
962
+ const { showDroppableSuggestion } = useDragLayer((monitor) => ({
963
+ showDroppableSuggestion:
964
+ monitor.isDragging() &&
965
+ (monitor.getItemType() === QUERY_BUILDER_PROJECTION_COLUMN_DND_TYPE ||
966
+ monitor.getItemType() === QUERY_BUILDER_WINDOW_COLUMN_DND_TYPE),
967
+ }));
968
+
895
969
  return (
896
- <div
897
- data-testid={QUERY_BUILDER_TEST_ID.QUERY_BUILDER_POST_FILTER}
898
- className="panel"
899
- >
970
+ <>
900
971
  <div className="panel__header">
901
972
  <div className="panel__header__title">
902
973
  <div className="panel__header__title__label">post-filter</div>
@@ -980,7 +1051,11 @@ const QueryBuilderPostFilterPanelContent = observer(
980
1051
  </div>
981
1052
  <PanelContent>
982
1053
  <PanelDropZone
983
- isDragOver={isDragOver}
1054
+ isDragOver={isDragOver && postFilterState.isEmpty}
1055
+ showDroppableSuggestion={
1056
+ showDroppableSuggestion && postFilterState.isEmpty
1057
+ }
1058
+ className="query-builder__panel--droppable"
984
1059
  dropTargetConnector={dropTargetConnector}
985
1060
  >
986
1061
  {postFilterState.isEmpty && (
@@ -1000,9 +1075,23 @@ const QueryBuilderPostFilterPanelContent = observer(
1000
1075
  <QueryBuilderPostFilterTree tdsState={tdsState} />
1001
1076
  </>
1002
1077
  )}
1078
+
1079
+ {showDroppableSuggestion && (
1080
+ <div
1081
+ ref={dropTargetConnector}
1082
+ className={clsx(
1083
+ 'query-builder-post-filter-tree__blank-node--droppable--tall',
1084
+ {
1085
+ 'dnd__entry--droppable__indicator--dragover': isDragOver,
1086
+ },
1087
+ )}
1088
+ >
1089
+ Add post-filter to main group
1090
+ </div>
1091
+ )}
1003
1092
  </PanelDropZone>
1004
1093
  </PanelContent>
1005
- </div>
1094
+ </>
1006
1095
  );
1007
1096
  },
1008
1097
  );
@@ -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
  );