@finos/legend-query-builder 4.14.62 → 4.14.64

Sign up to get free protection for your applications and to get access to all the features.
Files changed (104) hide show
  1. package/lib/components/QueryBuilderSideBar.js +1 -1
  2. package/lib/components/QueryBuilderSideBar.js.map +1 -1
  3. package/lib/components/QueryLoader.js +1 -1
  4. package/lib/components/QueryLoader.js.map +1 -1
  5. package/lib/components/__test-utils__/QueryBuilderComponentTestUtils.d.ts +3 -0
  6. package/lib/components/__test-utils__/QueryBuilderComponentTestUtils.d.ts.map +1 -1
  7. package/lib/components/__test-utils__/QueryBuilderComponentTestUtils.js +12 -1
  8. package/lib/components/__test-utils__/QueryBuilderComponentTestUtils.js.map +1 -1
  9. package/lib/components/fetch-structure/QueryBuilderPostFilterPanel.d.ts.map +1 -1
  10. package/lib/components/fetch-structure/QueryBuilderPostFilterPanel.js +20 -19
  11. package/lib/components/fetch-structure/QueryBuilderPostFilterPanel.js.map +1 -1
  12. package/lib/components/filter/QueryBuilderFilterPanel.d.ts +7 -1
  13. package/lib/components/filter/QueryBuilderFilterPanel.d.ts.map +1 -1
  14. package/lib/components/filter/QueryBuilderFilterPanel.js +137 -54
  15. package/lib/components/filter/QueryBuilderFilterPanel.js.map +1 -1
  16. package/lib/components/shared/CustomDatePicker.js +1 -1
  17. package/lib/components/shared/CustomDatePicker.js.map +1 -1
  18. package/lib/components/shared/QueryBuilderFilterHelper.d.ts +19 -0
  19. package/lib/components/shared/QueryBuilderFilterHelper.d.ts.map +1 -0
  20. package/lib/components/shared/QueryBuilderFilterHelper.js +34 -0
  21. package/lib/components/shared/QueryBuilderFilterHelper.js.map +1 -0
  22. package/lib/components/shared/QueryBuilderPropertyInfoTooltip.js +1 -1
  23. package/lib/components/shared/QueryBuilderPropertyInfoTooltip.js.map +1 -1
  24. package/lib/index.css +2 -2
  25. package/lib/index.css.map +1 -1
  26. package/lib/package.json +6 -6
  27. package/lib/stores/QueryBuilderStateHashUtils.d.ts +2 -0
  28. package/lib/stores/QueryBuilderStateHashUtils.d.ts.map +1 -1
  29. package/lib/stores/QueryBuilderStateHashUtils.js +2 -0
  30. package/lib/stores/QueryBuilderStateHashUtils.js.map +1 -1
  31. package/lib/stores/explorer/QueryBuilderExplorerState.js +1 -1
  32. package/lib/stores/explorer/QueryBuilderExplorerState.js.map +1 -1
  33. package/lib/stores/fetch-structure/tds/post-filter/operators/QueryBuilderPostFilterOperator_In.js +1 -1
  34. package/lib/stores/fetch-structure/tds/post-filter/operators/QueryBuilderPostFilterOperator_In.js.map +1 -1
  35. package/lib/stores/filter/QueryBuilderFilterState.d.ts +35 -5
  36. package/lib/stores/filter/QueryBuilderFilterState.d.ts.map +1 -1
  37. package/lib/stores/filter/QueryBuilderFilterState.js +181 -52
  38. package/lib/stores/filter/QueryBuilderFilterState.js.map +1 -1
  39. package/lib/stores/filter/QueryBuilderFilterStateBuilder.js +2 -2
  40. package/lib/stores/filter/QueryBuilderFilterStateBuilder.js.map +1 -1
  41. package/lib/stores/filter/operators/QueryBuilderFilterOperatorValueSpecificationBuilder.d.ts.map +1 -1
  42. package/lib/stores/filter/operators/QueryBuilderFilterOperatorValueSpecificationBuilder.js +21 -6
  43. package/lib/stores/filter/operators/QueryBuilderFilterOperatorValueSpecificationBuilder.js.map +1 -1
  44. package/lib/stores/filter/operators/QueryBuilderFilterOperator_Contain.d.ts.map +1 -1
  45. package/lib/stores/filter/operators/QueryBuilderFilterOperator_Contain.js +4 -3
  46. package/lib/stores/filter/operators/QueryBuilderFilterOperator_Contain.js.map +1 -1
  47. package/lib/stores/filter/operators/QueryBuilderFilterOperator_EndWith.d.ts.map +1 -1
  48. package/lib/stores/filter/operators/QueryBuilderFilterOperator_EndWith.js +4 -3
  49. package/lib/stores/filter/operators/QueryBuilderFilterOperator_EndWith.js.map +1 -1
  50. package/lib/stores/filter/operators/QueryBuilderFilterOperator_Equal.d.ts.map +1 -1
  51. package/lib/stores/filter/operators/QueryBuilderFilterOperator_Equal.js +5 -4
  52. package/lib/stores/filter/operators/QueryBuilderFilterOperator_Equal.js.map +1 -1
  53. package/lib/stores/filter/operators/QueryBuilderFilterOperator_GreaterThan.d.ts.map +1 -1
  54. package/lib/stores/filter/operators/QueryBuilderFilterOperator_GreaterThan.js +5 -4
  55. package/lib/stores/filter/operators/QueryBuilderFilterOperator_GreaterThan.js.map +1 -1
  56. package/lib/stores/filter/operators/QueryBuilderFilterOperator_GreaterThanEqual.d.ts.map +1 -1
  57. package/lib/stores/filter/operators/QueryBuilderFilterOperator_GreaterThanEqual.js +5 -4
  58. package/lib/stores/filter/operators/QueryBuilderFilterOperator_GreaterThanEqual.js.map +1 -1
  59. package/lib/stores/filter/operators/QueryBuilderFilterOperator_In.d.ts +1 -1
  60. package/lib/stores/filter/operators/QueryBuilderFilterOperator_In.d.ts.map +1 -1
  61. package/lib/stores/filter/operators/QueryBuilderFilterOperator_In.js +33 -28
  62. package/lib/stores/filter/operators/QueryBuilderFilterOperator_In.js.map +1 -1
  63. package/lib/stores/filter/operators/QueryBuilderFilterOperator_IsEmpty.js +1 -1
  64. package/lib/stores/filter/operators/QueryBuilderFilterOperator_IsEmpty.js.map +1 -1
  65. package/lib/stores/filter/operators/QueryBuilderFilterOperator_LessThan.d.ts.map +1 -1
  66. package/lib/stores/filter/operators/QueryBuilderFilterOperator_LessThan.js +5 -4
  67. package/lib/stores/filter/operators/QueryBuilderFilterOperator_LessThan.js.map +1 -1
  68. package/lib/stores/filter/operators/QueryBuilderFilterOperator_LessThanEqual.d.ts.map +1 -1
  69. package/lib/stores/filter/operators/QueryBuilderFilterOperator_LessThanEqual.js +5 -4
  70. package/lib/stores/filter/operators/QueryBuilderFilterOperator_LessThanEqual.js.map +1 -1
  71. package/lib/stores/filter/operators/QueryBuilderFilterOperator_StartWith.d.ts.map +1 -1
  72. package/lib/stores/filter/operators/QueryBuilderFilterOperator_StartWith.js +4 -3
  73. package/lib/stores/filter/operators/QueryBuilderFilterOperator_StartWith.js.map +1 -1
  74. package/lib/stores/shared/ValueSpecificationEditorHelper.d.ts +2 -1
  75. package/lib/stores/shared/ValueSpecificationEditorHelper.d.ts.map +1 -1
  76. package/lib/stores/shared/ValueSpecificationEditorHelper.js +9 -3
  77. package/lib/stores/shared/ValueSpecificationEditorHelper.js.map +1 -1
  78. package/package.json +14 -14
  79. package/src/components/QueryBuilderSideBar.tsx +1 -1
  80. package/src/components/QueryLoader.tsx +2 -2
  81. package/src/components/__test-utils__/QueryBuilderComponentTestUtils.tsx +25 -0
  82. package/src/components/fetch-structure/QueryBuilderPostFilterPanel.tsx +29 -26
  83. package/src/components/filter/QueryBuilderFilterPanel.tsx +335 -106
  84. package/src/components/shared/CustomDatePicker.tsx +1 -1
  85. package/src/components/shared/QueryBuilderFilterHelper.ts +51 -0
  86. package/src/components/shared/QueryBuilderPropertyInfoTooltip.tsx +1 -1
  87. package/src/stores/QueryBuilderStateHashUtils.ts +2 -0
  88. package/src/stores/explorer/QueryBuilderExplorerState.ts +1 -1
  89. package/src/stores/fetch-structure/tds/post-filter/operators/QueryBuilderPostFilterOperator_In.ts +1 -1
  90. package/src/stores/filter/QueryBuilderFilterState.ts +284 -74
  91. package/src/stores/filter/QueryBuilderFilterStateBuilder.ts +2 -2
  92. package/src/stores/filter/operators/QueryBuilderFilterOperatorValueSpecificationBuilder.ts +48 -9
  93. package/src/stores/filter/operators/QueryBuilderFilterOperator_Contain.ts +5 -4
  94. package/src/stores/filter/operators/QueryBuilderFilterOperator_EndWith.ts +5 -4
  95. package/src/stores/filter/operators/QueryBuilderFilterOperator_Equal.ts +4 -4
  96. package/src/stores/filter/operators/QueryBuilderFilterOperator_GreaterThan.ts +5 -7
  97. package/src/stores/filter/operators/QueryBuilderFilterOperator_GreaterThanEqual.ts +5 -7
  98. package/src/stores/filter/operators/QueryBuilderFilterOperator_In.ts +52 -47
  99. package/src/stores/filter/operators/QueryBuilderFilterOperator_IsEmpty.ts +1 -1
  100. package/src/stores/filter/operators/QueryBuilderFilterOperator_LessThan.ts +5 -7
  101. package/src/stores/filter/operators/QueryBuilderFilterOperator_LessThanEqual.ts +5 -7
  102. package/src/stores/filter/operators/QueryBuilderFilterOperator_StartWith.ts +5 -4
  103. package/src/stores/shared/ValueSpecificationEditorHelper.ts +28 -0
  104. package/tsconfig.json +1 -0
@@ -50,10 +50,11 @@ import {
50
50
  MenuContentItemIcon,
51
51
  MenuContentItemLabel,
52
52
  InfoCircleIcon,
53
+ RefreshIcon,
53
54
  } from '@finos/legend-art';
54
55
  import {
55
56
  type QueryBuilderFilterConditionDragSource,
56
- type QueryBuilderFilterDropTarget,
57
+ type QueryBuilderFilterNodeDropTarget,
57
58
  type QueryBuilderFilterTreeNodeData,
58
59
  QUERY_BUILDER_FILTER_DND_TYPE,
59
60
  FilterConditionState,
@@ -63,6 +64,10 @@ import {
63
64
  QueryBuilderFilterTreeExistsNodeData,
64
65
  QueryBuilderFilterTreeOperationNodeData,
65
66
  type QueryBuilderFilterState,
67
+ FilterValueSpecConditionValueState,
68
+ FilterPropertyExpressionStateConditionValueState,
69
+ isCollectionProperty,
70
+ type QueryBuilderFilterValueDropTarget,
66
71
  } from '../../stores/filter/QueryBuilderFilterState.js';
67
72
  import { useDrag, useDragLayer, useDrop } from 'react-dnd';
68
73
  import {
@@ -80,7 +85,6 @@ import {
80
85
  assertTrue,
81
86
  debounce,
82
87
  generateEnumerableNameFromToken,
83
- getNullableFirstEntry,
84
88
  guaranteeNonNullable,
85
89
  guaranteeType,
86
90
  UnsupportedOperationError,
@@ -92,14 +96,17 @@ import {
92
96
  useApplicationStore,
93
97
  } from '@finos/legend-application';
94
98
  import {
99
+ type Type,
100
+ type ValueSpecification,
95
101
  AbstractPropertyExpression,
96
102
  extractElementNameFromPath,
97
103
  matchFunctionName,
98
104
  Multiplicity,
99
105
  SimpleFunctionExpression,
100
- type ValueSpecification,
101
106
  VariableExpression,
102
107
  PrimitiveType,
108
+ Class,
109
+ Enumeration,
103
110
  } from '@finos/legend-graph';
104
111
  import {
105
112
  type QueryBuilderProjectionColumnDragSource,
@@ -115,11 +122,24 @@ import {
115
122
  EditableBasicValueSpecificationEditor,
116
123
  } from '../shared/BasicValueSpecificationEditor.js';
117
124
  import { QueryBuilderTelemetryHelper } from '../../__lib__/QueryBuilderTelemetryHelper.js';
118
- import { getPropertyChainName } from '../../stores/QueryBuilderPropertyEditorState.js';
125
+ import {
126
+ QueryBuilderPropertyExpressionState,
127
+ getPropertyChainName,
128
+ } from '../../stores/QueryBuilderPropertyEditorState.js';
119
129
  import { QUERY_BUILDER_SUPPORTED_FUNCTIONS } from '../../graph/QueryBuilderMetaModelConst.js';
120
130
  import { buildPropertyExpressionChain } from '../../stores/QueryBuilderValueSpecificationBuilderHelper.js';
121
131
  import { QueryBuilderPanelIssueCountBadge } from '../shared/QueryBuilderPanelIssueCountBadge.js';
122
- import { convertTextToPrimitiveInstanceValue } from '../../stores/shared/ValueSpecificationEditorHelper.js';
132
+ import {
133
+ cloneAbstractPropertyExpression,
134
+ convertTextToPrimitiveInstanceValue,
135
+ } from '../../stores/shared/ValueSpecificationEditorHelper.js';
136
+ import {
137
+ QueryBuilderFilterOperator_In,
138
+ QueryBuilderFilterOperator_NotIn,
139
+ } from '../../stores/filter/operators/QueryBuilderFilterOperator_In.js';
140
+ import { renderPropertyTypeIcon } from '../fetch-structure/QueryBuilderTDSComponentHelper.js';
141
+ import { QueryBuilderPropertyInfoTooltip } from '../shared/QueryBuilderPropertyInfoTooltip.js';
142
+ import { getDNDItemType } from '../shared/QueryBuilderFilterHelper.js';
123
143
 
124
144
  export const CAN_DROP_MAIN_GROUP_DND_TYPES_FETCH_SUPPORTED = [
125
145
  QUERY_BUILDER_EXPLORER_TREE_DND_TYPE.ENUM_PROPERTY,
@@ -146,40 +166,12 @@ export const CAN_DROP_FILTER_NODE_DND_TYPES = [
146
166
  ];
147
167
 
148
168
  export const CAN_DROP_FILTER_VALUE_DND_TYPES = [
169
+ QUERY_BUILDER_EXPLORER_TREE_DND_TYPE.ENUM_PROPERTY,
170
+ QUERY_BUILDER_EXPLORER_TREE_DND_TYPE.PRIMITIVE_PROPERTY,
171
+ QUERY_BUILDER_PROJECTION_COLUMN_DND_TYPE,
149
172
  QUERY_BUILDER_VARIABLE_DND_TYPE,
150
173
  ];
151
174
 
152
- const isCollectionProperty = (
153
- propertyExpression: AbstractPropertyExpression,
154
- ): boolean => {
155
- let currentExpression: ValueSpecification | undefined = propertyExpression;
156
- while (currentExpression instanceof AbstractPropertyExpression) {
157
- // Check if the property chain can results in column that have multiple values
158
- if (
159
- currentExpression.func.value.multiplicity.upperBound === undefined ||
160
- currentExpression.func.value.multiplicity.upperBound > 1
161
- ) {
162
- return true;
163
- }
164
- currentExpression = getNullableFirstEntry(
165
- currentExpression.parametersValues,
166
- );
167
- // Take care of chains of subtype
168
- while (
169
- currentExpression instanceof SimpleFunctionExpression &&
170
- matchFunctionName(
171
- currentExpression.functionName,
172
- QUERY_BUILDER_SUPPORTED_FUNCTIONS.SUBTYPE,
173
- )
174
- ) {
175
- currentExpression = getNullableFirstEntry(
176
- currentExpression.parametersValues,
177
- );
178
- }
179
- }
180
- return false;
181
- };
182
-
183
175
  /**
184
176
  * This function updates the filter state when we DnD a property that can accept multiple values.
185
177
  */
@@ -742,6 +734,91 @@ const QueryBuilderFilterExistsConditionEditor = observer(
742
734
  },
743
735
  );
744
736
 
737
+ export const QueryBuilderFilterPropertyExpressionBadge = observer(
738
+ (props: {
739
+ rightConditionValue: FilterPropertyExpressionStateConditionValueState;
740
+ resetNode: () => void;
741
+ }) => {
742
+ const { rightConditionValue, resetNode } = props;
743
+ const type = rightConditionValue.type;
744
+
745
+ return (
746
+ <div className="query-builder-filter-property-expression-badge">
747
+ <div className="query-builder-filter-property-expression-badge__content">
748
+ <div
749
+ className={clsx(
750
+ 'query-builder-filter-property-expression-badge__type',
751
+ {
752
+ 'query-builder-filter-property-expression-badge__type--class':
753
+ type instanceof Class,
754
+ 'query-builder-filter-property-expression-badge__type--enumeration':
755
+ type instanceof Enumeration,
756
+ 'query-builder-filter-property-expression-badge__type--primitive':
757
+ type instanceof PrimitiveType,
758
+ },
759
+ )}
760
+ >
761
+ {renderPropertyTypeIcon(type)}
762
+ </div>
763
+ <div
764
+ className="query-builder-filter-property-expression-badge__property"
765
+ title={
766
+ rightConditionValue.propertyExpressionState.propertyExpression
767
+ .func.value.name
768
+ }
769
+ >
770
+ <QueryBuilderPropertyExpressionBadge
771
+ propertyExpressionState={
772
+ rightConditionValue.propertyExpressionState
773
+ }
774
+ />
775
+ </div>
776
+ <QueryBuilderPropertyInfoTooltip
777
+ title={
778
+ rightConditionValue.propertyExpressionState.propertyExpression
779
+ .func.value.name
780
+ }
781
+ property={
782
+ rightConditionValue.propertyExpressionState.propertyExpression
783
+ .func.value
784
+ }
785
+ path={rightConditionValue.propertyExpressionState.path}
786
+ isMapped={true}
787
+ placement="bottom-end"
788
+ >
789
+ <div className="query-builder-filter-property-expression-badge__property__info">
790
+ <InfoCircleIcon />
791
+ </div>
792
+ </QueryBuilderPropertyInfoTooltip>
793
+ <button
794
+ className="query-builder-filter-property-expression-badge__action"
795
+ name="Reset"
796
+ title="Reset"
797
+ onClick={resetNode}
798
+ >
799
+ <RefreshIcon />
800
+ </button>
801
+ </div>
802
+ </div>
803
+ );
804
+ },
805
+ );
806
+
807
+ const canDropTypeOntoNodeValue = (
808
+ type: Type | undefined,
809
+ condition: FilterConditionState,
810
+ ): boolean => {
811
+ const conditionOperator = condition.operator;
812
+ const conditionValueType =
813
+ condition.propertyExpressionState.propertyExpression.func.value.genericType
814
+ .value.rawType;
815
+ return (
816
+ !(conditionOperator instanceof QueryBuilderFilterOperator_In) &&
817
+ !(conditionOperator instanceof QueryBuilderFilterOperator_NotIn) &&
818
+ isTypeCompatibleForAssignment(type, conditionValueType)
819
+ );
820
+ };
821
+
745
822
  const QueryBuilderFilterConditionEditor = observer(
746
823
  (props: {
747
824
  node: QueryBuilderFilterTreeConditionNodeData;
@@ -751,26 +828,114 @@ const QueryBuilderFilterConditionEditor = observer(
751
828
  const graph =
752
829
  node.condition.filterState.queryBuilderState.graphManagerState.graph;
753
830
  const queryBuilderState = node.condition.filterState.queryBuilderState;
831
+ const rightConditionValue = node.condition.rightConditionValue;
754
832
  const applicationStore = useApplicationStore();
755
- const changeOperator = (val: QueryBuilderFilterOperator) => (): void =>
756
- node.condition.changeOperator(val);
833
+
757
834
  // Drag and Drop on filter condition value
758
835
  const handleDrop = useCallback(
759
- (item: QueryBuilderVariableDragSource): void => {
760
- const parameterType = item.variable.genericType?.value.rawType;
761
- const conditionValueType =
762
- node.condition.propertyExpressionState.propertyExpression.func.value
763
- .genericType.value.rawType;
764
- if (isTypeCompatibleForAssignment(parameterType, conditionValueType)) {
765
- node.condition.setValue(item.variable);
836
+ (item: QueryBuilderFilterValueDropTarget, type: string): void => {
837
+ const itemType = getDNDItemType(item, type);
838
+ if (
839
+ itemType !== undefined &&
840
+ canDropTypeOntoNodeValue(itemType, node.condition)
841
+ ) {
842
+ try {
843
+ if (
844
+ (type === QUERY_BUILDER_PROJECTION_COLUMN_DND_TYPE ||
845
+ type === QUERY_BUILDER_EXPLORER_TREE_DND_TYPE.ENUM_PROPERTY ||
846
+ type ===
847
+ QUERY_BUILDER_EXPLORER_TREE_DND_TYPE.PRIMITIVE_PROPERTY) &&
848
+ node.isExistsNodeChild
849
+ ) {
850
+ throw new UnsupportedOperationError(
851
+ 'Collection filter does not support property for filter condition value.',
852
+ );
853
+ }
854
+ if (type === QUERY_BUILDER_PROJECTION_COLUMN_DND_TYPE) {
855
+ const columnState = (
856
+ item as QueryBuilderProjectionColumnDragSource
857
+ ).columnState;
858
+ if (
859
+ columnState instanceof QueryBuilderSimpleProjectionColumnState
860
+ ) {
861
+ const columnPropertyExpression =
862
+ columnState.propertyExpressionState.propertyExpression;
863
+ if (isCollectionProperty(columnPropertyExpression)) {
864
+ throw new UnsupportedOperationError(
865
+ 'Collection types are not supported for filter condition values.',
866
+ );
867
+ } else {
868
+ node.condition.buildRightConditionValueFromPropertyExpressionState(
869
+ new QueryBuilderPropertyExpressionState(
870
+ queryBuilderState,
871
+ cloneAbstractPropertyExpression(
872
+ columnPropertyExpression,
873
+ queryBuilderState.observerContext,
874
+ ),
875
+ ),
876
+ );
877
+ }
878
+ } else {
879
+ throw new UnsupportedOperationError(
880
+ 'Derivation projection columns are not supported for filter condition values.',
881
+ );
882
+ }
883
+ } else if (
884
+ type === QUERY_BUILDER_EXPLORER_TREE_DND_TYPE.ENUM_PROPERTY ||
885
+ type === QUERY_BUILDER_EXPLORER_TREE_DND_TYPE.PRIMITIVE_PROPERTY
886
+ ) {
887
+ const explorerNode = (item as QueryBuilderExplorerTreeDragSource)
888
+ .node;
889
+ const propertyExpressionState =
890
+ new QueryBuilderPropertyExpressionState(
891
+ queryBuilderState,
892
+ buildPropertyExpressionFromExplorerTreeNodeData(
893
+ explorerNode,
894
+ node.condition.filterState.queryBuilderState.explorerState,
895
+ ),
896
+ );
897
+ if (
898
+ isCollectionProperty(propertyExpressionState.propertyExpression)
899
+ ) {
900
+ throw new UnsupportedOperationError(
901
+ 'Collection types are not supported for filter condition values.',
902
+ );
903
+ } else {
904
+ node.condition.buildRightConditionValueFromPropertyExpressionState(
905
+ propertyExpressionState,
906
+ );
907
+ }
908
+ } else if (type === QUERY_BUILDER_VARIABLE_DND_TYPE) {
909
+ const variable = (item as QueryBuilderVariableDragSource)
910
+ .variable;
911
+ node.condition.buildRightConditionValueFromValueSpec(variable);
912
+ } else {
913
+ applicationStore.notificationService.notifyWarning(
914
+ `Dragging and Dropping ${type} to filter panel is not supported.`,
915
+ );
916
+ }
917
+ } catch (error) {
918
+ assertErrorThrown(error);
919
+ applicationStore.notificationService.notifyWarning(error.message);
920
+ return;
921
+ }
766
922
  } else {
923
+ const conditionValueType =
924
+ node.condition.propertyExpressionState.propertyExpression.func.value
925
+ .genericType.value.rawType;
767
926
  applicationStore.notificationService.notifyWarning(
768
- `Incompatible parameter type ${parameterType?.name}. ${parameterType?.name} is not compatible with type ${conditionValueType.name}.`,
927
+ `Incompatible parameter type ${itemType?.name}. ${itemType?.name} is not compatible with type ${conditionValueType.name}.`,
769
928
  );
770
929
  }
771
930
  },
772
- [applicationStore, node.condition],
931
+ [
932
+ applicationStore,
933
+ queryBuilderState,
934
+ node.condition,
935
+ node.isExistsNodeChild,
936
+ ],
773
937
  );
938
+
774
939
  const [{ isFilterValueDragOver }, dropConnector] = useDrop<
775
940
  QueryBuilderVariableDragSource,
776
941
  void,
@@ -778,23 +943,54 @@ const QueryBuilderFilterConditionEditor = observer(
778
943
  >(
779
944
  () => ({
780
945
  accept: CAN_DROP_FILTER_VALUE_DND_TYPES,
946
+ canDrop: (item, monitor): boolean =>
947
+ canDropTypeOntoNodeValue(
948
+ getDNDItemType(item, monitor.getItemType() as string),
949
+ node.condition,
950
+ ),
781
951
  drop: (item, monitor): void => {
782
952
  if (!monitor.didDrop()) {
783
- handleDrop(item);
953
+ handleDrop(item, monitor.getItemType() as string);
784
954
  } // prevent drop event propagation to accomondate for nested DnD
785
955
  },
786
956
  collect: (monitor) => ({
787
- isFilterValueDragOver: monitor.isOver({ shallow: true }),
957
+ isFilterValueDragOver:
958
+ monitor.isOver({ shallow: true }) && monitor.canDrop(),
788
959
  }),
789
960
  }),
790
961
  [handleDrop],
791
962
  );
792
963
 
964
+ const { isFilterValueDroppable } = useDragLayer((monitor) => ({
965
+ isFilterValueDroppable:
966
+ monitor.isDragging() &&
967
+ CAN_DROP_FILTER_VALUE_DND_TYPES.includes(
968
+ monitor.getItemType()?.toString() ?? '',
969
+ ) &&
970
+ canDropTypeOntoNodeValue(
971
+ getDNDItemType(monitor.getItem(), monitor.getItemType() as string),
972
+ node.condition,
973
+ ),
974
+ }));
975
+
976
+ // actions
977
+ const changeOperator = (val: QueryBuilderFilterOperator) => (): void =>
978
+ node.condition.changeOperator(val);
979
+
793
980
  const resetNode = (): void => {
794
- node.condition.setValue(
981
+ node.condition.buildRightConditionValueFromValueSpec(
795
982
  node.condition.operator.getDefaultFilterConditionValue(node.condition),
796
983
  );
797
984
  };
985
+
986
+ const cleanUpReloadValues = (): void => {
987
+ node.condition.typeaheadSearchState.complete();
988
+ };
989
+
990
+ const changeValueSpecification = (val: ValueSpecification): void => {
991
+ node.condition.buildRightConditionValueFromValueSpec(val);
992
+ };
993
+
798
994
  const debouncedTypeaheadSearch = useMemo(
799
995
  () =>
800
996
  debounce((inputValue: string) => {
@@ -809,12 +1005,7 @@ const QueryBuilderFilterConditionEditor = observer(
809
1005
  }, 1000),
810
1006
  [node, queryBuilderState.observerContext],
811
1007
  );
812
- const cleanUpReloadValues = (): void => {
813
- node.condition.typeaheadSearchState.complete();
814
- };
815
- const changeValueSpecification = (val: ValueSpecification): void => {
816
- node.condition.setValue(val);
817
- };
1008
+
818
1009
  const selectorConfig = {
819
1010
  values: node.condition.typeaheadSearchResults,
820
1011
  isLoading: node.condition.typeaheadSearchState.isInProgress,
@@ -822,6 +1013,69 @@ const QueryBuilderFilterConditionEditor = observer(
822
1013
  cleanUpReloadValues,
823
1014
  };
824
1015
 
1016
+ const renderRightValue = (): React.ReactNode => {
1017
+ if (
1018
+ rightConditionValue instanceof FilterValueSpecConditionValueState &&
1019
+ rightConditionValue.value
1020
+ ) {
1021
+ return (
1022
+ <div
1023
+ ref={dropConnector}
1024
+ data-testid={
1025
+ QUERY_BUILDER_TEST_ID.QUERY_BUILDER_FILTER_TREE_CONDITION_NODE_VALUE
1026
+ }
1027
+ className="query-builder-filter-tree__condition-node__value"
1028
+ >
1029
+ <PanelEntryDropZonePlaceholder
1030
+ isDragOver={isFilterValueDragOver}
1031
+ isDroppable={isFilterValueDroppable}
1032
+ label="Change Filter Value"
1033
+ >
1034
+ <EditableBasicValueSpecificationEditor
1035
+ valueSpecification={rightConditionValue.value}
1036
+ setValueSpecification={changeValueSpecification}
1037
+ graph={graph}
1038
+ observerContext={queryBuilderState.observerContext}
1039
+ typeCheckOption={{
1040
+ expectedType:
1041
+ node.condition.propertyExpressionState.propertyExpression
1042
+ .func.value.genericType.value.rawType,
1043
+ }}
1044
+ resetValue={resetNode}
1045
+ selectorConfig={selectorConfig}
1046
+ isConstant={queryBuilderState.constantState.isValueSpecConstant(
1047
+ rightConditionValue.value,
1048
+ )}
1049
+ initializeAsEditable={node.isNewlyAdded}
1050
+ />
1051
+ </PanelEntryDropZonePlaceholder>
1052
+ </div>
1053
+ );
1054
+ } else if (
1055
+ rightConditionValue instanceof
1056
+ FilterPropertyExpressionStateConditionValueState
1057
+ ) {
1058
+ return (
1059
+ <div
1060
+ ref={dropConnector}
1061
+ className="query-builder-filter-tree__condition-node__value"
1062
+ >
1063
+ <PanelEntryDropZonePlaceholder
1064
+ isDragOver={isFilterValueDragOver}
1065
+ isDroppable={isFilterValueDroppable}
1066
+ label="Change Filter Value"
1067
+ >
1068
+ <QueryBuilderFilterPropertyExpressionBadge
1069
+ rightConditionValue={rightConditionValue}
1070
+ resetNode={resetNode}
1071
+ />
1072
+ </PanelEntryDropZonePlaceholder>
1073
+ </div>
1074
+ );
1075
+ }
1076
+ return null;
1077
+ };
1078
+
825
1079
  useEffect(() => {
826
1080
  node.setIsNewlyAdded(false);
827
1081
  }, [node]);
@@ -834,8 +1088,8 @@ const QueryBuilderFilterConditionEditor = observer(
834
1088
  }
835
1089
  >
836
1090
  <PanelEntryDropZonePlaceholder
837
- isDragOver={isDragOver}
838
- label="Add New Logical Group"
1091
+ isDragOver={isDragOver && !isFilterValueDragOver}
1092
+ alwaysShowChildren={true}
839
1093
  >
840
1094
  <div className="query-builder-filter-tree__condition-node">
841
1095
  <div className="query-builder-filter-tree__condition-node__property">
@@ -872,39 +1126,7 @@ const QueryBuilderFilterConditionEditor = observer(
872
1126
  <CaretDownIcon />
873
1127
  </div>
874
1128
  </ControlledDropdownMenu>
875
- {node.condition.value && (
876
- <div
877
- ref={dropConnector}
878
- data-testid={
879
- QUERY_BUILDER_TEST_ID.QUERY_BUILDER_FILTER_TREE_CONDITION_NODE_VALUE
880
- }
881
- className="query-builder-filter-tree__condition-node__value"
882
- >
883
- <PanelEntryDropZonePlaceholder
884
- isDragOver={isFilterValueDragOver}
885
- label="Change Filter Value"
886
- >
887
- <EditableBasicValueSpecificationEditor
888
- valueSpecification={node.condition.value}
889
- setValueSpecification={changeValueSpecification}
890
- graph={graph}
891
- observerContext={queryBuilderState.observerContext}
892
- typeCheckOption={{
893
- expectedType:
894
- node.condition.propertyExpressionState
895
- .propertyExpression.func.value.genericType.value
896
- .rawType,
897
- }}
898
- resetValue={resetNode}
899
- selectorConfig={selectorConfig}
900
- isConstant={queryBuilderState.constantState.isValueSpecConstant(
901
- node.condition.value,
902
- )}
903
- initializeAsEditable={node.isNewlyAdded}
904
- />
905
- </PanelEntryDropZonePlaceholder>
906
- </div>
907
- )}
1129
+ {renderRightValue()}
908
1130
  </div>
909
1131
  </PanelEntryDropZonePlaceholder>
910
1132
  </div>
@@ -1005,7 +1227,7 @@ const QueryBuilderFilterTreeNodeContainer = observer(
1005
1227
 
1006
1228
  // Drag and Drop
1007
1229
  const handleDrop = useCallback(
1008
- (item: QueryBuilderFilterDropTarget, type: string): void => {
1230
+ (item: QueryBuilderFilterNodeDropTarget, type: string): void => {
1009
1231
  if (QUERY_BUILDER_FILTER_DND_TYPE.CONDITION === type) {
1010
1232
  const nodeBeingDragged = (
1011
1233
  item as QueryBuilderFilterConditionDragSource
@@ -1041,10 +1263,13 @@ const QueryBuilderFilterTreeNodeContainer = observer(
1041
1263
  .columnState instanceof
1042
1264
  QueryBuilderSimpleProjectionColumnState
1043
1265
  ) {
1044
- propertyExpression = (
1045
- (item as QueryBuilderProjectionColumnDragSource)
1046
- .columnState as QueryBuilderSimpleProjectionColumnState
1047
- ).propertyExpressionState.propertyExpression;
1266
+ propertyExpression = cloneAbstractPropertyExpression(
1267
+ (
1268
+ (item as QueryBuilderProjectionColumnDragSource)
1269
+ .columnState as QueryBuilderSimpleProjectionColumnState
1270
+ ).propertyExpressionState.propertyExpression,
1271
+ queryBuilderState.observerContext,
1272
+ );
1048
1273
  } else {
1049
1274
  throw new UnsupportedOperationError(
1050
1275
  `Dragging and Dropping derivation projection column is not supported.`,
@@ -1089,12 +1314,12 @@ const QueryBuilderFilterTreeNodeContainer = observer(
1089
1314
  }
1090
1315
  }
1091
1316
  },
1092
- [applicationStore, filterState, node],
1317
+ [applicationStore, filterState, node, queryBuilderState.observerContext],
1093
1318
  );
1094
- const [{ isDragOver }, dropConnector] = useDrop<
1319
+ const [{ isDragOver, deepIsDragOver }, dropConnector] = useDrop<
1095
1320
  QueryBuilderFilterConditionDragSource,
1096
1321
  void,
1097
- { isDragOver: boolean }
1322
+ { isDragOver: boolean; deepIsDragOver: boolean }
1098
1323
  >(
1099
1324
  () => ({
1100
1325
  accept:
@@ -1108,6 +1333,7 @@ const QueryBuilderFilterTreeNodeContainer = observer(
1108
1333
  },
1109
1334
  collect: (monitor) => ({
1110
1335
  isDragOver: monitor.isOver({ shallow: true }),
1336
+ deepIsDragOver: monitor.isOver({ shallow: false }),
1111
1337
  }),
1112
1338
  }),
1113
1339
  [handleDrop],
@@ -1222,7 +1448,7 @@ const QueryBuilderFilterTreeNodeContainer = observer(
1222
1448
  {node instanceof QueryBuilderFilterTreeConditionNodeData && (
1223
1449
  <QueryBuilderFilterConditionEditor
1224
1450
  node={node}
1225
- isDragOver={isDragOver}
1451
+ isDragOver={deepIsDragOver}
1226
1452
  />
1227
1453
  )}
1228
1454
  {node instanceof QueryBuilderFilterTreeBlankConditionNodeData && (
@@ -1430,7 +1656,7 @@ export const QueryBuilderFilterPanel = observer(
1430
1656
 
1431
1657
  // Drag and Drop
1432
1658
  const handleDrop = useCallback(
1433
- (item: QueryBuilderFilterDropTarget, type: string): void => {
1659
+ (item: QueryBuilderFilterNodeDropTarget, type: string): void => {
1434
1660
  try {
1435
1661
  let propertyExpression;
1436
1662
  if (type === QUERY_BUILDER_PROJECTION_COLUMN_DND_TYPE) {
@@ -1438,10 +1664,13 @@ export const QueryBuilderFilterPanel = observer(
1438
1664
  (item as QueryBuilderProjectionColumnDragSource)
1439
1665
  .columnState instanceof QueryBuilderSimpleProjectionColumnState
1440
1666
  ) {
1441
- propertyExpression = (
1442
- (item as QueryBuilderProjectionColumnDragSource)
1443
- .columnState as QueryBuilderSimpleProjectionColumnState
1444
- ).propertyExpressionState.propertyExpression;
1667
+ propertyExpression = cloneAbstractPropertyExpression(
1668
+ (
1669
+ (item as QueryBuilderProjectionColumnDragSource)
1670
+ .columnState as QueryBuilderSimpleProjectionColumnState
1671
+ ).propertyExpressionState.propertyExpression,
1672
+ queryBuilderState.observerContext,
1673
+ );
1445
1674
  } else {
1446
1675
  throw new UnsupportedOperationError(
1447
1676
  `Dragging and Dropping derivation projection column is not supported.`,
@@ -1463,7 +1692,7 @@ export const QueryBuilderFilterPanel = observer(
1463
1692
  return;
1464
1693
  }
1465
1694
  },
1466
- [applicationStore, filterState],
1695
+ [applicationStore, filterState, queryBuilderState.observerContext],
1467
1696
  );
1468
1697
 
1469
1698
  const [{ isDragOver }, dropTargetConnector] = useDrop<
@@ -977,7 +977,7 @@ const CustomDateInstanceValueEditor: React.FC<{
977
977
  ) => {
978
978
  const duration =
979
979
  event.target.value !== ''
980
- ? returnUndefOnError(() => parseNumber(event.target.value)) ?? 0
980
+ ? (returnUndefOnError(() => parseNumber(event.target.value)) ?? 0)
981
981
  : 0;
982
982
  setDurationValue(duration);
983
983
  changeValue(duration, unitValue, directionValue, referenceMomentValue);
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Copyright (c) 2020-present, Goldman Sachs
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ import type { Type } from '@finos/legend-graph';
18
+ import {
19
+ QUERY_BUILDER_EXPLORER_TREE_DND_TYPE,
20
+ type QueryBuilderExplorerTreeDragSource,
21
+ } from '../../stores/explorer/QueryBuilderExplorerState.js';
22
+ import {
23
+ QUERY_BUILDER_PROJECTION_COLUMN_DND_TYPE,
24
+ type QueryBuilderProjectionColumnDragSource,
25
+ } from '../../stores/fetch-structure/tds/projection/QueryBuilderProjectionColumnState.js';
26
+ import type { QueryBuilderFilterValueDropTarget } from '../../stores/filter/QueryBuilderFilterState.js';
27
+ import {
28
+ QUERY_BUILDER_VARIABLE_DND_TYPE,
29
+ type QueryBuilderVariableDragSource,
30
+ } from './BasicValueSpecificationEditor.js';
31
+
32
+ export const getDNDItemType = (
33
+ item: QueryBuilderFilterValueDropTarget,
34
+ type: string,
35
+ ): Type | undefined => {
36
+ switch (type) {
37
+ case QUERY_BUILDER_PROJECTION_COLUMN_DND_TYPE:
38
+ return (
39
+ item as QueryBuilderProjectionColumnDragSource
40
+ ).columnState.getColumnType();
41
+ case QUERY_BUILDER_EXPLORER_TREE_DND_TYPE.ENUM_PROPERTY:
42
+ case QUERY_BUILDER_EXPLORER_TREE_DND_TYPE.PRIMITIVE_PROPERTY:
43
+ return (item as QueryBuilderExplorerTreeDragSource).node.property
44
+ .genericType.value.rawType;
45
+ case QUERY_BUILDER_VARIABLE_DND_TYPE:
46
+ return (item as QueryBuilderVariableDragSource).variable.genericType
47
+ ?.value.rawType;
48
+ default:
49
+ return undefined;
50
+ }
51
+ };
@@ -214,7 +214,7 @@ export const QueryBuilderPropertyInfoTooltip: React.FC<{
214
214
  onClick={() => explorerState.highlightTreeNode(path)}
215
215
  title="Show in tree"
216
216
  >
217
- <ShareBoxIcon color="white" />
217
+ <ShareBoxIcon />
218
218
  </button>
219
219
  </div>
220
220
  ) : undefined,