@finos/legend-query-builder 4.0.8 → 4.0.10

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 (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
  );