@finos/legend-query-builder 4.14.63 → 4.14.65

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. package/lib/components/__test-utils__/QueryBuilderComponentTestUtils.d.ts +3 -0
  2. package/lib/components/__test-utils__/QueryBuilderComponentTestUtils.d.ts.map +1 -1
  3. package/lib/components/__test-utils__/QueryBuilderComponentTestUtils.js +12 -1
  4. package/lib/components/__test-utils__/QueryBuilderComponentTestUtils.js.map +1 -1
  5. package/lib/components/fetch-structure/QueryBuilderPostFilterPanel.d.ts.map +1 -1
  6. package/lib/components/fetch-structure/QueryBuilderPostFilterPanel.js +20 -19
  7. package/lib/components/fetch-structure/QueryBuilderPostFilterPanel.js.map +1 -1
  8. package/lib/components/filter/QueryBuilderFilterPanel.d.ts +7 -1
  9. package/lib/components/filter/QueryBuilderFilterPanel.d.ts.map +1 -1
  10. package/lib/components/filter/QueryBuilderFilterPanel.js +137 -54
  11. package/lib/components/filter/QueryBuilderFilterPanel.js.map +1 -1
  12. package/lib/components/shared/QueryBuilderFilterHelper.d.ts +19 -0
  13. package/lib/components/shared/QueryBuilderFilterHelper.d.ts.map +1 -0
  14. package/lib/components/shared/QueryBuilderFilterHelper.js +34 -0
  15. package/lib/components/shared/QueryBuilderFilterHelper.js.map +1 -0
  16. package/lib/components/shared/QueryBuilderPropertyInfoTooltip.js +1 -1
  17. package/lib/components/shared/QueryBuilderPropertyInfoTooltip.js.map +1 -1
  18. package/lib/index.css +17 -1
  19. package/lib/index.css.map +1 -1
  20. package/lib/package.json +3 -3
  21. package/lib/stores/QueryBuilderStateHashUtils.d.ts +2 -0
  22. package/lib/stores/QueryBuilderStateHashUtils.d.ts.map +1 -1
  23. package/lib/stores/QueryBuilderStateHashUtils.js +2 -0
  24. package/lib/stores/QueryBuilderStateHashUtils.js.map +1 -1
  25. package/lib/stores/fetch-structure/tds/post-filter/operators/QueryBuilderPostFilterOperator_In.js +1 -1
  26. package/lib/stores/fetch-structure/tds/post-filter/operators/QueryBuilderPostFilterOperator_In.js.map +1 -1
  27. package/lib/stores/filter/QueryBuilderFilterState.d.ts +35 -5
  28. package/lib/stores/filter/QueryBuilderFilterState.d.ts.map +1 -1
  29. package/lib/stores/filter/QueryBuilderFilterState.js +181 -52
  30. package/lib/stores/filter/QueryBuilderFilterState.js.map +1 -1
  31. package/lib/stores/filter/QueryBuilderFilterStateBuilder.js +2 -2
  32. package/lib/stores/filter/QueryBuilderFilterStateBuilder.js.map +1 -1
  33. package/lib/stores/filter/operators/QueryBuilderFilterOperatorValueSpecificationBuilder.d.ts.map +1 -1
  34. package/lib/stores/filter/operators/QueryBuilderFilterOperatorValueSpecificationBuilder.js +21 -6
  35. package/lib/stores/filter/operators/QueryBuilderFilterOperatorValueSpecificationBuilder.js.map +1 -1
  36. package/lib/stores/filter/operators/QueryBuilderFilterOperator_Contain.d.ts.map +1 -1
  37. package/lib/stores/filter/operators/QueryBuilderFilterOperator_Contain.js +4 -3
  38. package/lib/stores/filter/operators/QueryBuilderFilterOperator_Contain.js.map +1 -1
  39. package/lib/stores/filter/operators/QueryBuilderFilterOperator_EndWith.d.ts.map +1 -1
  40. package/lib/stores/filter/operators/QueryBuilderFilterOperator_EndWith.js +4 -3
  41. package/lib/stores/filter/operators/QueryBuilderFilterOperator_EndWith.js.map +1 -1
  42. package/lib/stores/filter/operators/QueryBuilderFilterOperator_Equal.d.ts.map +1 -1
  43. package/lib/stores/filter/operators/QueryBuilderFilterOperator_Equal.js +5 -4
  44. package/lib/stores/filter/operators/QueryBuilderFilterOperator_Equal.js.map +1 -1
  45. package/lib/stores/filter/operators/QueryBuilderFilterOperator_GreaterThan.d.ts.map +1 -1
  46. package/lib/stores/filter/operators/QueryBuilderFilterOperator_GreaterThan.js +5 -4
  47. package/lib/stores/filter/operators/QueryBuilderFilterOperator_GreaterThan.js.map +1 -1
  48. package/lib/stores/filter/operators/QueryBuilderFilterOperator_GreaterThanEqual.d.ts.map +1 -1
  49. package/lib/stores/filter/operators/QueryBuilderFilterOperator_GreaterThanEqual.js +5 -4
  50. package/lib/stores/filter/operators/QueryBuilderFilterOperator_GreaterThanEqual.js.map +1 -1
  51. package/lib/stores/filter/operators/QueryBuilderFilterOperator_In.d.ts +1 -1
  52. package/lib/stores/filter/operators/QueryBuilderFilterOperator_In.d.ts.map +1 -1
  53. package/lib/stores/filter/operators/QueryBuilderFilterOperator_In.js +33 -28
  54. package/lib/stores/filter/operators/QueryBuilderFilterOperator_In.js.map +1 -1
  55. package/lib/stores/filter/operators/QueryBuilderFilterOperator_IsEmpty.js +1 -1
  56. package/lib/stores/filter/operators/QueryBuilderFilterOperator_IsEmpty.js.map +1 -1
  57. package/lib/stores/filter/operators/QueryBuilderFilterOperator_LessThan.d.ts.map +1 -1
  58. package/lib/stores/filter/operators/QueryBuilderFilterOperator_LessThan.js +5 -4
  59. package/lib/stores/filter/operators/QueryBuilderFilterOperator_LessThan.js.map +1 -1
  60. package/lib/stores/filter/operators/QueryBuilderFilterOperator_LessThanEqual.d.ts.map +1 -1
  61. package/lib/stores/filter/operators/QueryBuilderFilterOperator_LessThanEqual.js +5 -4
  62. package/lib/stores/filter/operators/QueryBuilderFilterOperator_LessThanEqual.js.map +1 -1
  63. package/lib/stores/filter/operators/QueryBuilderFilterOperator_StartWith.d.ts.map +1 -1
  64. package/lib/stores/filter/operators/QueryBuilderFilterOperator_StartWith.js +4 -3
  65. package/lib/stores/filter/operators/QueryBuilderFilterOperator_StartWith.js.map +1 -1
  66. package/lib/stores/shared/ValueSpecificationEditorHelper.d.ts +2 -1
  67. package/lib/stores/shared/ValueSpecificationEditorHelper.d.ts.map +1 -1
  68. package/lib/stores/shared/ValueSpecificationEditorHelper.js +9 -3
  69. package/lib/stores/shared/ValueSpecificationEditorHelper.js.map +1 -1
  70. package/package.json +11 -11
  71. package/src/components/__test-utils__/QueryBuilderComponentTestUtils.tsx +25 -0
  72. package/src/components/fetch-structure/QueryBuilderPostFilterPanel.tsx +29 -26
  73. package/src/components/filter/QueryBuilderFilterPanel.tsx +335 -106
  74. package/src/components/shared/QueryBuilderFilterHelper.ts +51 -0
  75. package/src/components/shared/QueryBuilderPropertyInfoTooltip.tsx +1 -1
  76. package/src/stores/QueryBuilderStateHashUtils.ts +2 -0
  77. package/src/stores/fetch-structure/tds/post-filter/operators/QueryBuilderPostFilterOperator_In.ts +1 -1
  78. package/src/stores/filter/QueryBuilderFilterState.ts +284 -74
  79. package/src/stores/filter/QueryBuilderFilterStateBuilder.ts +2 -2
  80. package/src/stores/filter/operators/QueryBuilderFilterOperatorValueSpecificationBuilder.ts +48 -9
  81. package/src/stores/filter/operators/QueryBuilderFilterOperator_Contain.ts +5 -4
  82. package/src/stores/filter/operators/QueryBuilderFilterOperator_EndWith.ts +5 -4
  83. package/src/stores/filter/operators/QueryBuilderFilterOperator_Equal.ts +4 -4
  84. package/src/stores/filter/operators/QueryBuilderFilterOperator_GreaterThan.ts +5 -7
  85. package/src/stores/filter/operators/QueryBuilderFilterOperator_GreaterThanEqual.ts +5 -7
  86. package/src/stores/filter/operators/QueryBuilderFilterOperator_In.ts +52 -47
  87. package/src/stores/filter/operators/QueryBuilderFilterOperator_IsEmpty.ts +1 -1
  88. package/src/stores/filter/operators/QueryBuilderFilterOperator_LessThan.ts +5 -7
  89. package/src/stores/filter/operators/QueryBuilderFilterOperator_LessThanEqual.ts +5 -7
  90. package/src/stores/filter/operators/QueryBuilderFilterOperator_StartWith.ts +5 -4
  91. package/src/stores/shared/ValueSpecificationEditorHelper.ts +28 -0
  92. 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<
@@ -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,
@@ -91,6 +91,8 @@ export enum QUERY_BUILDER_STATE_HASH_STRUCTURE {
91
91
  FILTER_TREE_CONDIITION_NODE_DATA = 'FILTER_TREE_CONDITION_NODE_DATA',
92
92
  FILTER_TREE_BLANK_CONDITION_NODE_DATA = 'FILTER_TREE_BLANK_CONDITION_NODE_DATA',
93
93
  FILTER_CONDITION_STATE = 'FILTER_CONDITION_STATE',
94
+ FILTER_CONDITION_RIGHT_VALUE = 'FILTER_CONDITION_RIGHT_VALUE',
95
+ FILTER_CONDITION_RIGHT_VALUE_SPEC = 'FILTER_CONDITION_RIGHT_VALUE_SPEC',
94
96
  FILTER_OPERATOR_CONTAIN = 'FILTER_OPERATOR_CONTAIN',
95
97
  FILTER_OPERATOR_NOT_CONTAIN = 'FILTER_OPERATOR_NOT_CONTAIN',
96
98
  FILTER_OPERATOR_END_WITH = 'FILTER_OPERATOR_END_WITH',