@finos/legend-application-query 5.0.1 → 5.2.1

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 (210) hide show
  1. package/lib/application/LegendQueryApplicationConfig.d.ts +17 -1
  2. package/lib/application/LegendQueryApplicationConfig.d.ts.map +1 -1
  3. package/lib/application/LegendQueryApplicationConfig.js +23 -1
  4. package/lib/application/LegendQueryApplicationConfig.js.map +1 -1
  5. package/lib/components/QueryBuilder.d.ts.map +1 -1
  6. package/lib/components/QueryBuilder.js +3 -1
  7. package/lib/components/QueryBuilder.js.map +1 -1
  8. package/lib/components/QueryBuilderExplorerPanel.d.ts.map +1 -1
  9. package/lib/components/QueryBuilderExplorerPanel.js +10 -35
  10. package/lib/components/QueryBuilderExplorerPanel.js.map +1 -1
  11. package/lib/components/QueryBuilderFetchStructurePanel.d.ts.map +1 -1
  12. package/lib/components/QueryBuilderFetchStructurePanel.js +78 -35
  13. package/lib/components/QueryBuilderFetchStructurePanel.js.map +1 -1
  14. package/lib/components/QueryBuilderFilterPanel.d.ts.map +1 -1
  15. package/lib/components/QueryBuilderFilterPanel.js +80 -66
  16. package/lib/components/QueryBuilderFilterPanel.js.map +1 -1
  17. package/lib/components/QueryBuilderFunctionsExplorerPanel.d.ts.map +1 -1
  18. package/lib/components/QueryBuilderFunctionsExplorerPanel.js +9 -39
  19. package/lib/components/QueryBuilderFunctionsExplorerPanel.js.map +1 -1
  20. package/lib/components/QueryBuilderGraphFetchTreePanel.d.ts.map +1 -1
  21. package/lib/components/QueryBuilderGraphFetchTreePanel.js +5 -5
  22. package/lib/components/QueryBuilderGraphFetchTreePanel.js.map +1 -1
  23. package/lib/components/QueryBuilderLambdaEditor.d.ts +1 -0
  24. package/lib/components/QueryBuilderLambdaEditor.d.ts.map +1 -1
  25. package/lib/components/QueryBuilderLambdaEditor.js +2 -2
  26. package/lib/components/QueryBuilderLambdaEditor.js.map +1 -1
  27. package/lib/components/QueryBuilderMilestoneEditor.js +5 -5
  28. package/lib/components/QueryBuilderMilestoneEditor.js.map +1 -1
  29. package/lib/components/QueryBuilderPanelIssueCountBadge.d.ts +20 -0
  30. package/lib/components/QueryBuilderPanelIssueCountBadge.d.ts.map +1 -0
  31. package/lib/components/QueryBuilderPanelIssueCountBadge.js +28 -0
  32. package/lib/components/QueryBuilderPanelIssueCountBadge.js.map +1 -0
  33. package/lib/components/QueryBuilderParameterPanel.d.ts.map +1 -1
  34. package/lib/components/QueryBuilderParameterPanel.js +13 -33
  35. package/lib/components/QueryBuilderParameterPanel.js.map +1 -1
  36. package/lib/components/QueryBuilderPostFilterPanel.d.ts.map +1 -1
  37. package/lib/components/QueryBuilderPostFilterPanel.js +59 -62
  38. package/lib/components/QueryBuilderPostFilterPanel.js.map +1 -1
  39. package/lib/components/QueryBuilderProjectionPanel.d.ts.map +1 -1
  40. package/lib/components/QueryBuilderProjectionPanel.js +47 -63
  41. package/lib/components/QueryBuilderProjectionPanel.js.map +1 -1
  42. package/lib/components/QueryBuilderPropertyExpressionEditor.d.ts.map +1 -1
  43. package/lib/components/QueryBuilderPropertyExpressionEditor.js +11 -11
  44. package/lib/components/QueryBuilderPropertyExpressionEditor.js.map +1 -1
  45. package/lib/components/QueryBuilderPropertySearchPanel.js +5 -7
  46. package/lib/components/QueryBuilderPropertySearchPanel.js.map +1 -1
  47. package/lib/components/QueryBuilderResultModifierPanel.d.ts.map +1 -1
  48. package/lib/components/QueryBuilderResultModifierPanel.js +3 -1
  49. package/lib/components/QueryBuilderResultModifierPanel.js.map +1 -1
  50. package/lib/components/QueryBuilderResultPanel.d.ts.map +1 -1
  51. package/lib/components/QueryBuilderResultPanel.js +37 -23
  52. package/lib/components/QueryBuilderResultPanel.js.map +1 -1
  53. package/lib/components/QueryBuilderSetupPanel.d.ts.map +1 -1
  54. package/lib/components/QueryBuilderSetupPanel.js +10 -9
  55. package/lib/components/QueryBuilderSetupPanel.js.map +1 -1
  56. package/lib/components/QueryBuilderUnsupportedQueryEditor.d.ts.map +1 -1
  57. package/lib/components/QueryBuilderUnsupportedQueryEditor.js +4 -2
  58. package/lib/components/QueryBuilderUnsupportedQueryEditor.js.map +1 -1
  59. package/lib/components/QueryEditor.d.ts.map +1 -1
  60. package/lib/components/QueryEditor.js +16 -4
  61. package/lib/components/QueryEditor.js.map +1 -1
  62. package/lib/index.css +2 -2
  63. package/lib/index.css.map +1 -1
  64. package/lib/package.json +10 -9
  65. package/lib/stores/QueryBuilderExplorerState.d.ts +1 -1
  66. package/lib/stores/QueryBuilderExplorerState.d.ts.map +1 -1
  67. package/lib/stores/QueryBuilderExplorerState.js +18 -3
  68. package/lib/stores/QueryBuilderExplorerState.js.map +1 -1
  69. package/lib/stores/QueryBuilderFetchStructureState.d.ts +8 -1
  70. package/lib/stores/QueryBuilderFetchStructureState.d.ts.map +1 -1
  71. package/lib/stores/QueryBuilderFetchStructureState.js +10 -2
  72. package/lib/stores/QueryBuilderFetchStructureState.js.map +1 -1
  73. package/lib/stores/QueryBuilderFilterState.d.ts +10 -5
  74. package/lib/stores/QueryBuilderFilterState.d.ts.map +1 -1
  75. package/lib/stores/QueryBuilderFilterState.js +34 -8
  76. package/lib/stores/QueryBuilderFilterState.js.map +1 -1
  77. package/lib/stores/QueryBuilderGraphFetchTreeState.d.ts.map +1 -1
  78. package/lib/stores/QueryBuilderGraphFetchTreeState.js +6 -3
  79. package/lib/stores/QueryBuilderGraphFetchTreeState.js.map +1 -1
  80. package/lib/stores/QueryBuilderLambdaProcessor.d.ts.map +1 -1
  81. package/lib/stores/QueryBuilderLambdaProcessor.js +2 -0
  82. package/lib/stores/QueryBuilderLambdaProcessor.js.map +1 -1
  83. package/lib/stores/QueryBuilderOperatorLoader.d.ts +47 -0
  84. package/lib/stores/QueryBuilderOperatorLoader.d.ts.map +1 -0
  85. package/lib/stores/QueryBuilderOperatorLoader.js +94 -0
  86. package/lib/stores/QueryBuilderOperatorLoader.js.map +1 -0
  87. package/lib/stores/QueryBuilderOperatorsHelper.d.ts +1 -0
  88. package/lib/stores/QueryBuilderOperatorsHelper.d.ts.map +1 -1
  89. package/lib/stores/QueryBuilderOperatorsHelper.js +28 -1
  90. package/lib/stores/QueryBuilderOperatorsHelper.js.map +1 -1
  91. package/lib/stores/QueryBuilderPostFilterState.d.ts +9 -6
  92. package/lib/stores/QueryBuilderPostFilterState.d.ts.map +1 -1
  93. package/lib/stores/QueryBuilderPostFilterState.js +31 -7
  94. package/lib/stores/QueryBuilderPostFilterState.js.map +1 -1
  95. package/lib/stores/QueryBuilderPreviewDataHelper.d.ts +4 -3
  96. package/lib/stores/QueryBuilderPreviewDataHelper.d.ts.map +1 -1
  97. package/lib/stores/QueryBuilderPreviewDataHelper.js +77 -97
  98. package/lib/stores/QueryBuilderPreviewDataHelper.js.map +1 -1
  99. package/lib/stores/QueryBuilderProjectionState.d.ts +4 -7
  100. package/lib/stores/QueryBuilderProjectionState.d.ts.map +1 -1
  101. package/lib/stores/QueryBuilderProjectionState.js +23 -39
  102. package/lib/stores/QueryBuilderProjectionState.js.map +1 -1
  103. package/lib/stores/QueryBuilderPropertySearchPanelState.js +1 -1
  104. package/lib/stores/QueryBuilderPropertySearchPanelState.js.map +1 -1
  105. package/lib/stores/QueryBuilderResultState.d.ts +5 -2
  106. package/lib/stores/QueryBuilderResultState.d.ts.map +1 -1
  107. package/lib/stores/QueryBuilderResultState.js +19 -7
  108. package/lib/stores/QueryBuilderResultState.js.map +1 -1
  109. package/lib/stores/QueryBuilderSetupState.js +1 -1
  110. package/lib/stores/QueryBuilderSetupState.js.map +1 -1
  111. package/lib/stores/QueryBuilderState.d.ts +7 -0
  112. package/lib/stores/QueryBuilderState.d.ts.map +1 -1
  113. package/lib/stores/QueryBuilderState.js +18 -58
  114. package/lib/stores/QueryBuilderState.js.map +1 -1
  115. package/lib/stores/QueryBuilderTestUtils.d.ts +24 -0
  116. package/lib/stores/QueryBuilderTestUtils.d.ts.map +1 -0
  117. package/lib/stores/QueryBuilderTestUtils.js +49 -0
  118. package/lib/stores/QueryBuilderTestUtils.js.map +1 -0
  119. package/lib/stores/QueryBuilderTypeaheadHelper.d.ts +24 -0
  120. package/lib/stores/QueryBuilderTypeaheadHelper.d.ts.map +1 -0
  121. package/lib/stores/QueryBuilderTypeaheadHelper.js +89 -0
  122. package/lib/stores/QueryBuilderTypeaheadHelper.js.map +1 -0
  123. package/lib/stores/QueryBuilderValueSpecificationBuilderHelper.d.ts.map +1 -1
  124. package/lib/stores/QueryBuilderValueSpecificationBuilderHelper.js +7 -7
  125. package/lib/stores/QueryBuilderValueSpecificationBuilderHelper.js.map +1 -1
  126. package/lib/stores/QueryEditorStore.d.ts.map +1 -1
  127. package/lib/stores/QueryEditorStore.js +14 -3
  128. package/lib/stores/QueryEditorStore.js.map +1 -1
  129. package/lib/stores/QueryFunctionsExplorerState.d.ts +2 -6
  130. package/lib/stores/QueryFunctionsExplorerState.d.ts.map +1 -1
  131. package/lib/stores/QueryFunctionsExplorerState.js +2 -11
  132. package/lib/stores/QueryFunctionsExplorerState.js.map +1 -1
  133. package/lib/stores/QueryParametersState.d.ts +1 -3
  134. package/lib/stores/QueryParametersState.d.ts.map +1 -1
  135. package/lib/stores/QueryParametersState.js +1 -4
  136. package/lib/stores/QueryParametersState.js.map +1 -1
  137. package/lib/stores/filterOperators/QueryBuilderFilterOperator_Equal.d.ts.map +1 -1
  138. package/lib/stores/filterOperators/QueryBuilderFilterOperator_Equal.js +9 -32
  139. package/lib/stores/filterOperators/QueryBuilderFilterOperator_Equal.js.map +1 -1
  140. package/lib/stores/filterOperators/QueryBuilderFilterOperator_GreaterThan.d.ts.map +1 -1
  141. package/lib/stores/filterOperators/QueryBuilderFilterOperator_GreaterThan.js +9 -32
  142. package/lib/stores/filterOperators/QueryBuilderFilterOperator_GreaterThan.js.map +1 -1
  143. package/lib/stores/filterOperators/QueryBuilderFilterOperator_GreaterThanEqual.d.ts.map +1 -1
  144. package/lib/stores/filterOperators/QueryBuilderFilterOperator_GreaterThanEqual.js +9 -32
  145. package/lib/stores/filterOperators/QueryBuilderFilterOperator_GreaterThanEqual.js.map +1 -1
  146. package/lib/stores/filterOperators/QueryBuilderFilterOperator_LessThan.d.ts.map +1 -1
  147. package/lib/stores/filterOperators/QueryBuilderFilterOperator_LessThan.js +9 -33
  148. package/lib/stores/filterOperators/QueryBuilderFilterOperator_LessThan.js.map +1 -1
  149. package/lib/stores/filterOperators/QueryBuilderFilterOperator_LessThanEqual.d.ts.map +1 -1
  150. package/lib/stores/filterOperators/QueryBuilderFilterOperator_LessThanEqual.js +9 -32
  151. package/lib/stores/filterOperators/QueryBuilderFilterOperator_LessThanEqual.js.map +1 -1
  152. package/lib/stores/postFilterOperators/QueryBuilderPostFilterOperator_Equal.d.ts.map +1 -1
  153. package/lib/stores/postFilterOperators/QueryBuilderPostFilterOperator_Equal.js +7 -30
  154. package/lib/stores/postFilterOperators/QueryBuilderPostFilterOperator_Equal.js.map +1 -1
  155. package/lib/stores/postFilterOperators/QueryBuilderPostFilterOperator_GreaterThan.d.ts.map +1 -1
  156. package/lib/stores/postFilterOperators/QueryBuilderPostFilterOperator_GreaterThan.js +8 -31
  157. package/lib/stores/postFilterOperators/QueryBuilderPostFilterOperator_GreaterThan.js.map +1 -1
  158. package/lib/stores/postFilterOperators/QueryBuilderPostFilterOperator_LessThan.d.ts.map +1 -1
  159. package/lib/stores/postFilterOperators/QueryBuilderPostFilterOperator_LessThan.js +8 -31
  160. package/lib/stores/postFilterOperators/QueryBuilderPostFilterOperator_LessThan.js.map +1 -1
  161. package/package.json +17 -16
  162. package/src/application/LegendQueryApplicationConfig.ts +35 -1
  163. package/src/components/QueryBuilder.tsx +13 -2
  164. package/src/components/QueryBuilderExplorerPanel.tsx +20 -57
  165. package/src/components/QueryBuilderFetchStructurePanel.tsx +94 -41
  166. package/src/components/QueryBuilderFilterPanel.tsx +271 -232
  167. package/src/components/QueryBuilderFunctionsExplorerPanel.tsx +24 -68
  168. package/src/components/QueryBuilderGraphFetchTreePanel.tsx +34 -25
  169. package/src/components/QueryBuilderLambdaEditor.tsx +3 -0
  170. package/src/components/QueryBuilderMilestoneEditor.tsx +34 -34
  171. package/src/components/QueryBuilderPanelIssueCountBadge.tsx +38 -0
  172. package/src/components/QueryBuilderParameterPanel.tsx +23 -55
  173. package/src/components/QueryBuilderPostFilterPanel.tsx +245 -233
  174. package/src/components/QueryBuilderProjectionPanel.tsx +127 -154
  175. package/src/components/QueryBuilderPropertyExpressionEditor.tsx +61 -57
  176. package/src/components/QueryBuilderPropertySearchPanel.tsx +9 -9
  177. package/src/components/QueryBuilderResultModifierPanel.tsx +4 -2
  178. package/src/components/QueryBuilderResultPanel.tsx +139 -91
  179. package/src/components/QueryBuilderSetupPanel.tsx +13 -12
  180. package/src/components/QueryBuilderUnsupportedQueryEditor.tsx +4 -2
  181. package/src/components/QueryEditor.tsx +39 -1
  182. package/src/stores/QueryBuilderExplorerState.ts +22 -3
  183. package/src/stores/QueryBuilderFetchStructureState.ts +18 -2
  184. package/src/stores/QueryBuilderFilterState.ts +52 -7
  185. package/src/stores/QueryBuilderGraphFetchTreeState.ts +14 -8
  186. package/src/stores/QueryBuilderLambdaProcessor.ts +8 -0
  187. package/src/stores/QueryBuilderOperatorLoader.ts +133 -0
  188. package/src/stores/QueryBuilderOperatorsHelper.ts +35 -0
  189. package/src/stores/QueryBuilderPostFilterState.ts +47 -8
  190. package/src/stores/QueryBuilderPreviewDataHelper.ts +122 -217
  191. package/src/stores/QueryBuilderProjectionState.ts +40 -53
  192. package/src/stores/QueryBuilderPropertySearchPanelState.ts +1 -1
  193. package/src/stores/QueryBuilderResultState.ts +27 -9
  194. package/src/stores/QueryBuilderSetupState.ts +1 -1
  195. package/src/stores/QueryBuilderState.ts +35 -94
  196. package/src/stores/QueryBuilderTestUtils.ts +93 -0
  197. package/src/stores/QueryBuilderTypeaheadHelper.ts +149 -0
  198. package/src/stores/QueryBuilderValueSpecificationBuilderHelper.ts +9 -7
  199. package/src/stores/QueryEditorStore.ts +19 -3
  200. package/src/stores/QueryFunctionsExplorerState.ts +1 -11
  201. package/src/stores/QueryParametersState.ts +1 -3
  202. package/src/stores/filterOperators/QueryBuilderFilterOperator_Equal.ts +14 -36
  203. package/src/stores/filterOperators/QueryBuilderFilterOperator_GreaterThan.ts +17 -36
  204. package/src/stores/filterOperators/QueryBuilderFilterOperator_GreaterThanEqual.ts +17 -36
  205. package/src/stores/filterOperators/QueryBuilderFilterOperator_LessThan.ts +17 -37
  206. package/src/stores/filterOperators/QueryBuilderFilterOperator_LessThanEqual.ts +17 -36
  207. package/src/stores/postFilterOperators/QueryBuilderPostFilterOperator_Equal.ts +14 -34
  208. package/src/stores/postFilterOperators/QueryBuilderPostFilterOperator_GreaterThan.ts +19 -37
  209. package/src/stores/postFilterOperators/QueryBuilderPostFilterOperator_LessThan.ts +19 -37
  210. package/tsconfig.json +4 -0
@@ -47,6 +47,10 @@ import {
47
47
  ToggleIcon,
48
48
  HashtagIcon,
49
49
  ClockIcon,
50
+ PanelDropZone,
51
+ DragPreviewLayer,
52
+ PanelEntryDropZonePlaceholder,
53
+ useDragPreviewLayer,
50
54
  } from '@finos/legend-art';
51
55
  import {
52
56
  type Type,
@@ -61,20 +65,18 @@ import {
61
65
  assertErrorThrown,
62
66
  guaranteeNonNullable,
63
67
  returnUndefOnError,
68
+ debounce,
64
69
  } from '@finos/legend-shared';
65
70
  import { flowResult } from 'mobx';
66
71
  import { observer } from 'mobx-react-lite';
67
- import { forwardRef, useCallback, useEffect, useRef, useState } from 'react';
68
- import {
69
- type DropTargetMonitor,
70
- useDragLayer,
71
- useDrop,
72
- useDrag,
73
- } from 'react-dnd';
74
- import { getEmptyImage } from 'react-dnd-html5-backend';
72
+ import { forwardRef, useCallback, useMemo, useRef, useState } from 'react';
73
+ import { useDrop, useDrag } from 'react-dnd';
75
74
  import { getColumnMultiplicity } from '../stores/postFilterOperators/QueryBuilderPostFilterOperatorHelper.js';
76
75
  import { QueryBuilderAggregateColumnState } from '../stores/QueryBuilderAggregationState.js';
77
- import { QUERY_BUILDER_GROUP_OPERATION } from '../stores/QueryBuilderOperatorsHelper.js';
76
+ import {
77
+ isTypeCompatibleWithConditionValueType,
78
+ QUERY_BUILDER_GROUP_OPERATION,
79
+ } from '../stores/QueryBuilderOperatorsHelper.js';
78
80
  import type { QueryBuilderPostFilterOperator } from '../stores/QueryBuilderPostFilterOperator.js';
79
81
  import {
80
82
  type QueryBuilderPostFilterTreeNodeData,
@@ -89,55 +91,16 @@ import {
89
91
  import {
90
92
  type QueryBuilderProjectionColumnState,
91
93
  type QueryBuilderProjectionColumnDragSource,
92
- QUERY_BUILDER_PROJECTION_DND_TYPE,
94
+ QUERY_BUILDER_PROJECTION_COLUMN_DND_TYPE,
93
95
  QueryBuilderDerivationProjectionColumnState,
94
96
  } from '../stores/QueryBuilderProjectionState.js';
95
97
  import type { QueryBuilderState } from '../stores/QueryBuilderState.js';
96
98
  import {
97
99
  type QueryBuilderParameterDragSource,
98
- QUERY_BUILDER_PARAMETER_TREE_DND_TYPE,
100
+ QUERY_BUILDER_PARAMETER_DND_TYPE,
99
101
  } from '../stores/QueryParametersState.js';
100
102
  import { QUERY_BUILDER_TEST_ID } from './QueryBuilder_TestID.js';
101
103
 
102
- const PostFilterConditionDragLayer: React.FC = () => {
103
- const { itemType, item, isDragging, currentPosition } = useDragLayer(
104
- (monitor) => ({
105
- itemType: monitor.getItemType() as QUERY_BUILDER_POST_FILTER_DND_TYPE,
106
- item: monitor.getItem<QueryBuilderPostFilterConditionDragSource | null>(),
107
- isDragging: monitor.isDragging(),
108
- initialOffset: monitor.getInitialSourceClientOffset(),
109
- currentPosition: monitor.getClientOffset(),
110
- }),
111
- );
112
-
113
- if (
114
- !isDragging ||
115
- !item ||
116
- !Object.values(QUERY_BUILDER_POST_FILTER_DND_TYPE).includes(itemType)
117
- ) {
118
- return null;
119
- }
120
- return (
121
- <div className="query-builder-post-filter-tree__drag-preview-layer">
122
- <div
123
- className="query-builder-post-filter-tree__drag-preview"
124
- // added some offset so the mouse doesn't overlap the label too much
125
- style={
126
- !currentPosition
127
- ? { display: 'none' }
128
- : {
129
- transform: `translate(${currentPosition.x + 20}px, ${
130
- currentPosition.y + 10
131
- }px)`,
132
- }
133
- }
134
- >
135
- {item.node.dragLayerLabel}
136
- </div>
137
- </div>
138
- );
139
- };
140
-
141
104
  const QueryBuilderPostFilterConditionContextMenu = observer(
142
105
  forwardRef<
143
106
  HTMLDivElement,
@@ -192,9 +155,9 @@ const QueryBuilderPostFilterConditionContextMenu = observer(
192
155
  const QueryBuilderPostFilterGroupConditionEditor = observer(
193
156
  (props: {
194
157
  node: QueryBuilderPostFilterTreeGroupNodeData;
195
- isPropertyDragOver: boolean;
158
+ isDragOver: boolean;
196
159
  }) => {
197
- const { node, isPropertyDragOver } = props;
160
+ const { node, isDragOver } = props;
198
161
  const switchOperation: React.MouseEventHandler<HTMLDivElement> = (
199
162
  event,
200
163
  ): void => {
@@ -206,29 +169,30 @@ const QueryBuilderPostFilterGroupConditionEditor = observer(
206
169
  );
207
170
  };
208
171
  return (
209
- <div className="query-builder-post-filter-tree__node__label__content dnd__overlay__container">
210
- {isPropertyDragOver && (
211
- <div className="query-builder-post-filter-tree__node__dnd__overlay">
212
- Add to Logical Group
213
- </div>
214
- )}
215
- <div
216
- className={clsx('query-builder-post-filter-tree__group-node', {
217
- 'query-builder-post-filter-tree__group-node--and':
218
- node.groupOperation === QUERY_BUILDER_GROUP_OPERATION.AND,
219
- 'query-builder-post-filter-tree__group-node--or':
220
- node.groupOperation === QUERY_BUILDER_GROUP_OPERATION.OR,
221
- })}
222
- title="Switch Operation"
223
- onClick={switchOperation}
172
+ <div className="query-builder-post-filter-tree__node__label__content">
173
+ <PanelEntryDropZonePlaceholder
174
+ showPlaceholder={isDragOver}
175
+ label="Add to Logical Group"
176
+ className="query-builder__dnd__placeholder"
224
177
  >
225
- <div className="query-builder-post-filter-tree__group-node__label">
226
- {node.groupOperation}
178
+ <div
179
+ className={clsx('query-builder-post-filter-tree__group-node', {
180
+ 'query-builder-post-filter-tree__group-node--and':
181
+ node.groupOperation === QUERY_BUILDER_GROUP_OPERATION.AND,
182
+ 'query-builder-post-filter-tree__group-node--or':
183
+ node.groupOperation === QUERY_BUILDER_GROUP_OPERATION.OR,
184
+ })}
185
+ title="Switch Operation"
186
+ onClick={switchOperation}
187
+ >
188
+ <div className="query-builder-post-filter-tree__group-node__label">
189
+ {node.groupOperation}
190
+ </div>
191
+ <button className="query-builder-post-filter-tree__group-node__action">
192
+ <FilledTriangleIcon />
193
+ </button>
227
194
  </div>
228
- <button className="query-builder-post-filter-tree__group-node__action">
229
- <FilledTriangleIcon />
230
- </button>
231
- </div>
195
+ </PanelEntryDropZonePlaceholder>
232
196
  </div>
233
197
  );
234
198
  },
@@ -333,22 +297,23 @@ export const QueryBuilderColumnBadge = observer(
333
297
  onColumnChange(item.columnState),
334
298
  [onColumnChange],
335
299
  );
336
- const [{ isPropertyDragOver }, dropConnector] = useDrop(
300
+ const [{ isDragOver }, dropConnector] = useDrop<
301
+ QueryBuilderProjectionColumnDragSource,
302
+ void,
303
+ { isDragOver: boolean }
304
+ >(
337
305
  () => ({
338
- accept: [QUERY_BUILDER_PROJECTION_DND_TYPE.PROJECTION_COLUMN],
339
- drop: (
340
- item: QueryBuilderProjectionColumnDragSource,
341
- monitor: DropTargetMonitor,
342
- ): void => {
306
+ accept: [QUERY_BUILDER_PROJECTION_COLUMN_DND_TYPE],
307
+ drop: (item, monitor): void => {
343
308
  if (!monitor.didDrop()) {
344
309
  handleDrop(item).catch(
345
310
  postFilterConditionState.postFilterState.queryBuilderState
346
311
  .applicationStore.alertUnhandledError,
347
312
  );
348
- }
313
+ } // prevent drop event propagation to accomondate for nested DnD
349
314
  },
350
- collect: (monitor): { isPropertyDragOver: boolean } => ({
351
- isPropertyDragOver: monitor.isOver({ shallow: true }),
315
+ collect: (monitor) => ({
316
+ isDragOver: monitor.isOver({ shallow: true }),
352
317
  }),
353
318
  }),
354
319
  [handleDrop],
@@ -356,12 +321,11 @@ export const QueryBuilderColumnBadge = observer(
356
321
 
357
322
  return (
358
323
  <div ref={dropConnector} className="query-builder-column-badge">
359
- {isPropertyDragOver && (
360
- <div className="query-builder__dnd__placeholder query-builder-column-badge__dnd__placeholder">
361
- Change Property
362
- </div>
363
- )}
364
- {!isPropertyDragOver && (
324
+ <PanelEntryDropZonePlaceholder
325
+ showPlaceholder={isDragOver}
326
+ label="Change Property"
327
+ className="query-builder__dnd__placeholder"
328
+ >
365
329
  <div className="query-builder-column-badge__content">
366
330
  {type && (
367
331
  <div
@@ -392,7 +356,7 @@ export const QueryBuilderColumnBadge = observer(
392
356
  </div>
393
357
  </QueryBuilderColumnInfoTooltip>
394
358
  </div>
395
- )}
359
+ </PanelEntryDropZonePlaceholder>
396
360
  </div>
397
361
  );
398
362
  },
@@ -400,11 +364,12 @@ export const QueryBuilderColumnBadge = observer(
400
364
  const QueryBuilderPostFilterConditionEditor = observer(
401
365
  (props: {
402
366
  node: QueryBuilderPostFilterTreeConditionNodeData;
403
- isPropertyDragOver: boolean;
367
+ isDragOver: boolean;
404
368
  }) => {
405
- const { node, isPropertyDragOver } = props;
369
+ const { node, isDragOver } = props;
406
370
  const graph =
407
371
  node.condition.postFilterState.queryBuilderState.graphManagerState.graph;
372
+ const applicationStore = useApplicationStore();
408
373
  const changeOperator = (val: QueryBuilderPostFilterOperator) => (): void =>
409
374
  node.condition.changeOperator(val);
410
375
  const changeColumn = async (
@@ -421,22 +386,38 @@ const QueryBuilderPostFilterConditionEditor = observer(
421
386
  // Drag and Drop on filter condition value
422
387
  const handleDrop = useCallback(
423
388
  (item: QueryBuilderParameterDragSource): void => {
424
- node.condition.setValue(item.variable.parameter);
389
+ const parameterType =
390
+ item.variable.parameter.genericType?.value.rawType;
391
+ const conditionValueType = node.condition.columnState.getReturnType();
392
+ if (
393
+ conditionValueType &&
394
+ isTypeCompatibleWithConditionValueType(
395
+ parameterType,
396
+ conditionValueType,
397
+ )
398
+ ) {
399
+ node.condition.setValue(item.variable.parameter);
400
+ } else {
401
+ applicationStore.notifyWarning(
402
+ `Incompatible parameter type ${parameterType?.name}. ${parameterType?.name} is not compatible with type ${conditionValueType?.name}.`,
403
+ );
404
+ }
425
405
  },
426
- [node],
406
+ [applicationStore, node.condition],
427
407
  );
428
- const [{ isFilterValueDragOver }, dropConnector] = useDrop(
408
+ const [{ isFilterValueDragOver }, dropConnector] = useDrop<
409
+ QueryBuilderParameterDragSource,
410
+ void,
411
+ { isFilterValueDragOver: boolean }
412
+ >(
429
413
  () => ({
430
- accept: [QUERY_BUILDER_PARAMETER_TREE_DND_TYPE.VARIABLE],
431
- drop: (
432
- item: QueryBuilderParameterDragSource,
433
- monitor: DropTargetMonitor,
434
- ): void => {
414
+ accept: [QUERY_BUILDER_PARAMETER_DND_TYPE],
415
+ drop: (item, monitor): void => {
435
416
  if (!monitor.didDrop()) {
436
417
  handleDrop(item);
437
- }
418
+ } // prevent drop event propagation to accomondate for nested DnD
438
419
  },
439
- collect: (monitor): { isFilterValueDragOver: boolean } => ({
420
+ collect: (monitor) => ({
440
421
  isFilterValueDragOver: monitor.isOver({ shallow: true }),
441
422
  }),
442
423
  }),
@@ -447,79 +428,100 @@ const QueryBuilderPostFilterConditionEditor = observer(
447
428
  node.condition.operator.getDefaultFilterConditionValue(node.condition),
448
429
  );
449
430
  };
431
+ const debouncedTypeaheadSearch = useMemo(
432
+ () =>
433
+ debounce(
434
+ (inputVal: string) => node.condition.handleTypeaheadSearch(),
435
+ 1000,
436
+ ),
437
+ [node],
438
+ );
439
+ const cleanUpReloadValues = (): void => {
440
+ node.condition.typeaheadSearchState.complete();
441
+ };
442
+ const changeValueSpecification = (val: ValueSpecification): void => {
443
+ node.condition.setValue(val);
444
+ };
445
+ const selectorConfig = {
446
+ values: node.condition.typeaheadSearchResults,
447
+ isLoading: node.condition.typeaheadSearchState.isInProgress,
448
+ reloadValues: debouncedTypeaheadSearch,
449
+ cleanUpReloadValues,
450
+ };
450
451
 
451
452
  return (
452
- <div className="query-builder-post-filter-tree__node__label__content dnd__overlay__container">
453
- {isPropertyDragOver && (
454
- <div className="query-builder-post-filter-tree__node__dnd__overlay">
455
- Add New Logical Group
456
- </div>
457
- )}
458
- <div className="query-builder-post-filter-tree__condition-node">
459
- <div className="query-builder-post-filter-tree__condition-node__property">
460
- <QueryBuilderColumnBadge
461
- postFilterConditionState={node.condition}
462
- onColumnChange={changeColumn}
463
- />
464
- </div>
465
- <DropdownMenu
466
- className="query-builder-post-filter-tree__condition-node__operator"
467
- content={
468
- <MenuContent>
469
- {node.condition.operators.map((op) => (
470
- <MenuContentItem
471
- key={op.uuid}
472
- className="query-builder-post-filter-tree__condition-node__operator__dropdown__option"
473
- onClick={changeOperator(op)}
474
- >
475
- {op.getLabel()}
476
- </MenuContentItem>
477
- ))}
478
- </MenuContent>
479
- }
480
- menuProps={{
481
- anchorOrigin: { vertical: 'bottom', horizontal: 'left' },
482
- transformOrigin: { vertical: 'top', horizontal: 'left' },
483
- elevation: 7,
484
- }}
485
- >
486
- <div className="query-builder-post-filter-tree__condition-node__operator__label">
487
- {node.condition.operator.getLabel()}
488
- </div>
489
- <button
490
- className="query-builder-post-filter-tree__condition-node__operator__dropdown__trigger"
491
- tabIndex={-1}
492
- title="Choose Operator..."
493
- >
494
- <CaretDownIcon />
495
- </button>
496
- </DropdownMenu>
497
- {node.condition.value && (
498
- <div
499
- ref={dropConnector}
500
- className="query-builder-post-filter-tree__condition-node__value dnd__overlay__container"
501
- >
502
- {isFilterValueDragOver && (
503
- <div className="query-builder-post-filter-tree__node__dnd__overlay">
504
- Change Filter Value
505
- </div>
506
- )}
507
- <BasicValueSpecificationEditor
508
- valueSpecification={node.condition.value}
509
- setValueSpecification={(val: ValueSpecification): void =>
510
- node.condition.setValue(val)
511
- }
512
- graph={graph}
513
- typeCheckOption={{
514
- expectedType: guaranteeNonNullable(
515
- node.condition.columnState.getReturnType(),
516
- ),
517
- }}
518
- resetValue={resetNode}
453
+ <div className="query-builder-post-filter-tree__node__label__content">
454
+ <PanelEntryDropZonePlaceholder
455
+ showPlaceholder={isDragOver}
456
+ label="Add New Logical Group"
457
+ className="query-builder__dnd__placeholder"
458
+ >
459
+ <div className="query-builder-post-filter-tree__condition-node">
460
+ <div className="query-builder-post-filter-tree__condition-node__property">
461
+ <QueryBuilderColumnBadge
462
+ postFilterConditionState={node.condition}
463
+ onColumnChange={changeColumn}
519
464
  />
520
465
  </div>
521
- )}
522
- </div>
466
+ <DropdownMenu
467
+ className="query-builder-post-filter-tree__condition-node__operator"
468
+ content={
469
+ <MenuContent>
470
+ {node.condition.operators.map((op) => (
471
+ <MenuContentItem
472
+ key={op.uuid}
473
+ className="query-builder-post-filter-tree__condition-node__operator__dropdown__option"
474
+ onClick={changeOperator(op)}
475
+ >
476
+ {op.getLabel()}
477
+ </MenuContentItem>
478
+ ))}
479
+ </MenuContent>
480
+ }
481
+ menuProps={{
482
+ anchorOrigin: { vertical: 'bottom', horizontal: 'left' },
483
+ transformOrigin: { vertical: 'top', horizontal: 'left' },
484
+ elevation: 7,
485
+ }}
486
+ >
487
+ <div className="query-builder-post-filter-tree__condition-node__operator__label">
488
+ {node.condition.operator.getLabel()}
489
+ </div>
490
+ <button
491
+ className="query-builder-post-filter-tree__condition-node__operator__dropdown__trigger"
492
+ tabIndex={-1}
493
+ title="Choose Operator..."
494
+ >
495
+ <CaretDownIcon />
496
+ </button>
497
+ </DropdownMenu>
498
+ {node.condition.value && (
499
+ <div
500
+ ref={dropConnector}
501
+ className="query-builder-post-filter-tree__condition-node__value"
502
+ >
503
+ <PanelEntryDropZonePlaceholder
504
+ showPlaceholder={isFilterValueDragOver}
505
+ label="Change Filter Value"
506
+ className="query-builder__dnd__placeholder"
507
+ >
508
+ <BasicValueSpecificationEditor
509
+ valueSpecification={node.condition.value}
510
+ setValueSpecification={changeValueSpecification}
511
+ graph={graph}
512
+ typeCheckOption={{
513
+ expectedType: guaranteeNonNullable(
514
+ node.condition.columnState.getReturnType(),
515
+ ),
516
+ }}
517
+ resetValue={resetNode}
518
+ selectorConfig={selectorConfig}
519
+ />
520
+ </PanelEntryDropZonePlaceholder>
521
+ </div>
522
+ )}
523
+ </div>
524
+ </PanelEntryDropZonePlaceholder>
523
525
  </div>
524
526
  );
525
527
  },
@@ -528,17 +530,20 @@ const QueryBuilderPostFilterConditionEditor = observer(
528
530
  const QueryBuilderPostFilterBlankConditionEditor = observer(
529
531
  (props: {
530
532
  node: QueryBuilderPostFilterTreeBlankConditionNodeData;
531
- isPropertyDragOver: boolean;
533
+ isDragOver: boolean;
532
534
  }) => {
533
- const { isPropertyDragOver } = props;
535
+ const { isDragOver } = props;
534
536
  return (
535
- <div className="query-builder-post-filter-tree__node__label__content dnd__overlay__container">
536
- {isPropertyDragOver && (
537
- <div className="query-builder-post-filter-tree__node__dnd__overlay">
538
- Create Condition
537
+ <div className="query-builder-post-filter-tree__node__label__content">
538
+ <PanelEntryDropZonePlaceholder
539
+ showPlaceholder={isDragOver}
540
+ label="Create Condition"
541
+ className="query-builder__dnd__placeholder"
542
+ >
543
+ <div className="query-builder-post-filter-tree__blank-node">
544
+ blank
539
545
  </div>
540
- )}
541
- <div className="query-builder-post-filter-tree__blank-node">blank</div>
546
+ </PanelEntryDropZonePlaceholder>
542
547
  </div>
543
548
  );
544
549
  },
@@ -568,7 +573,7 @@ const QueryBuilderPostFilterTreeNodeContainer = observer(
568
573
  postFilterState.removeNodeAndPruneBranch(node);
569
574
  const handleDrop = useCallback(
570
575
  (item: QueryBuilderPostFilterDropTarget, type: string): void => {
571
- if (type === QUERY_BUILDER_PROJECTION_DND_TYPE.PROJECTION_COLUMN) {
576
+ if (type === QUERY_BUILDER_PROJECTION_COLUMN_DND_TYPE) {
572
577
  const columnState = (item as QueryBuilderProjectionColumnDragSource)
573
578
  .columnState;
574
579
  let conditionState: PostFilterConditionState;
@@ -623,45 +628,45 @@ const QueryBuilderPostFilterTreeNodeContainer = observer(
623
628
  },
624
629
  [applicationStore, postFilterState, node],
625
630
  );
626
- const [{ isPropertyDragOver }, dropConnector] = useDrop(
631
+ const [{ isDragOver }, dropConnector] = useDrop<
632
+ QueryBuilderPostFilterConditionDragSource,
633
+ void,
634
+ { isDragOver: boolean }
635
+ >(
627
636
  () => ({
628
637
  accept: [
629
638
  ...Object.values(QUERY_BUILDER_POST_FILTER_DND_TYPE),
630
- QUERY_BUILDER_PROJECTION_DND_TYPE.PROJECTION_COLUMN,
639
+ QUERY_BUILDER_PROJECTION_COLUMN_DND_TYPE,
631
640
  ],
632
- drop: (
633
- item: QueryBuilderPostFilterConditionDragSource,
634
- monitor: DropTargetMonitor,
635
- ): void => {
641
+ drop: (item, monitor): void => {
636
642
  if (!monitor.didDrop()) {
637
643
  handleDrop(item, monitor.getItemType() as string);
638
644
  } // prevent drop event propagation to accomondate for nested DnD
639
645
  },
640
- collect: (monitor): { isPropertyDragOver: boolean } => ({
641
- isPropertyDragOver: monitor.isOver({ shallow: true }),
646
+ collect: (monitor) => ({
647
+ isDragOver: monitor.isOver({ shallow: true }),
642
648
  }),
643
649
  }),
644
650
  [handleDrop],
645
651
  );
646
652
 
647
- const [, dragConnector, dragPreviewConnector] = useDrag(
648
- () => ({
649
- type:
650
- node instanceof QueryBuilderPostFilterTreeGroupNodeData
651
- ? QUERY_BUILDER_POST_FILTER_DND_TYPE.GROUP_CONDITION
652
- : node instanceof QueryBuilderPostFilterTreeConditionNodeData
653
- ? QUERY_BUILDER_POST_FILTER_DND_TYPE.CONDITION
654
- : QUERY_BUILDER_POST_FILTER_DND_TYPE.BLANK_CONDITION,
655
- item: (): QueryBuilderPostFilterConditionDragSource => ({ node }),
656
- end: (): void => postFilterState.setRearrangingConditions(false),
657
- }),
658
- [node, postFilterState],
659
- );
653
+ const [, dragConnector, dragPreviewConnector] =
654
+ useDrag<QueryBuilderPostFilterConditionDragSource>(
655
+ () => ({
656
+ type:
657
+ node instanceof QueryBuilderPostFilterTreeGroupNodeData
658
+ ? QUERY_BUILDER_POST_FILTER_DND_TYPE.GROUP_CONDITION
659
+ : node instanceof QueryBuilderPostFilterTreeConditionNodeData
660
+ ? QUERY_BUILDER_POST_FILTER_DND_TYPE.CONDITION
661
+ : QUERY_BUILDER_POST_FILTER_DND_TYPE.BLANK_CONDITION,
662
+ item: () => ({ node }),
663
+ end: (): void => postFilterState.setRearrangingConditions(false),
664
+ }),
665
+ [node, postFilterState],
666
+ );
660
667
  dragConnector(dropConnector(ref));
661
- // hide default HTML5 preview image
662
- useEffect(() => {
663
- dragPreviewConnector(getEmptyImage(), { captureDraggingState: true });
664
- }, [dragPreviewConnector]);
668
+ useDragPreviewLayer(dragPreviewConnector);
669
+
665
670
  // context menu
666
671
  const onContextMenuOpen = (): void => setIsSelectedFromContextMenu(true);
667
672
  const onContextMenuClose = (): void => setIsSelectedFromContextMenu(false);
@@ -720,20 +725,20 @@ const QueryBuilderPostFilterTreeNodeContainer = observer(
720
725
  {node instanceof QueryBuilderPostFilterTreeGroupNodeData && (
721
726
  <QueryBuilderPostFilterGroupConditionEditor
722
727
  node={node}
723
- isPropertyDragOver={isPropertyDragOver}
728
+ isDragOver={isDragOver}
724
729
  />
725
730
  )}
726
731
  {node instanceof QueryBuilderPostFilterTreeConditionNodeData && (
727
732
  <QueryBuilderPostFilterConditionEditor
728
733
  node={node}
729
- isPropertyDragOver={isPropertyDragOver}
734
+ isDragOver={isDragOver}
730
735
  />
731
736
  )}
732
737
  {node instanceof
733
738
  QueryBuilderPostFilterTreeBlankConditionNodeData && (
734
739
  <QueryBuilderPostFilterBlankConditionEditor
735
740
  node={node}
736
- isPropertyDragOver={isPropertyDragOver}
741
+ isDragOver={isDragOver}
737
742
  />
738
743
  )}
739
744
  </div>
@@ -941,21 +946,22 @@ export const QueryBuilderPostFilterPanel = observer(
941
946
  .columns,
942
947
  ],
943
948
  );
944
- const [{ isPropertyDragOver }, dropConnector] = useDrop(
949
+ const [{ isDragOver }, dropTargetConnector] = useDrop<
950
+ QueryBuilderProjectionColumnDragSource,
951
+ void,
952
+ { isDragOver: boolean }
953
+ >(
945
954
  () => ({
946
- accept: [QUERY_BUILDER_PROJECTION_DND_TYPE.PROJECTION_COLUMN],
947
- drop: (
948
- item: QueryBuilderProjectionColumnDragSource,
949
- monitor: DropTargetMonitor,
950
- ): void => {
955
+ accept: [QUERY_BUILDER_PROJECTION_COLUMN_DND_TYPE],
956
+ drop: (item, monitor): void => {
951
957
  if (!monitor.didDrop()) {
952
958
  handleDrop(item).catch(
953
959
  queryBuilderState.applicationStore.alertUnhandledError,
954
960
  );
955
961
  } // prevent drop event propagation to accomondate for nested DnD
956
962
  },
957
- collect: (monitor): { isPropertyDragOver: boolean } => ({
958
- isPropertyDragOver: monitor.isOver({ shallow: true }),
963
+ collect: (monitor) => ({
964
+ isDragOver: monitor.isOver({ shallow: true }),
959
965
  }),
960
966
  }),
961
967
  [handleDrop],
@@ -1035,25 +1041,31 @@ export const QueryBuilderPostFilterPanel = observer(
1035
1041
  </button>
1036
1042
  </div>
1037
1043
  </div>
1038
- <div
1039
- className="panel__content query-builder__filter__content dnd__overlay__container"
1040
- ref={dropConnector}
1041
- >
1042
- <div className={clsx({ dnd__overlay: isPropertyDragOver })} />
1043
- {postFilterState.isEmpty && (
1044
- <BlankPanelPlaceholder
1045
- placeholderText="Add a post-filter condition"
1046
- tooltipText="Drag and drop properties here"
1047
- />
1048
- )}
1049
- {!postFilterState.isEmpty && (
1050
- <>
1051
- <PostFilterConditionDragLayer />
1052
- <QueryBuilderPostFilterTree
1053
- queryBuilderState={queryBuilderState}
1044
+ <div className="panel__content query-builder__filter__content">
1045
+ <PanelDropZone
1046
+ isDragOver={isDragOver}
1047
+ dropTargetConnector={dropTargetConnector}
1048
+ >
1049
+ {postFilterState.isEmpty && (
1050
+ <BlankPanelPlaceholder
1051
+ text="Add a post-filter condition"
1052
+ tooltipText="Drag and drop properties here"
1054
1053
  />
1055
- </>
1056
- )}
1054
+ )}
1055
+ {!postFilterState.isEmpty && (
1056
+ <>
1057
+ <DragPreviewLayer
1058
+ labelGetter={(
1059
+ item: QueryBuilderPostFilterConditionDragSource,
1060
+ ): string => item.node.dragPreviewLabel}
1061
+ types={Object.values(QUERY_BUILDER_POST_FILTER_DND_TYPE)}
1062
+ />
1063
+ <QueryBuilderPostFilterTree
1064
+ queryBuilderState={queryBuilderState}
1065
+ />
1066
+ </>
1067
+ )}
1068
+ </PanelDropZone>
1057
1069
  </div>
1058
1070
  </div>
1059
1071
  );