@finos/legend-query-builder 4.14.69 → 4.14.71

Sign up to get free protection for your applications and to get access to all the features.
Files changed (100) hide show
  1. package/lib/__lib__/QueryBuilderTesting.d.ts +1 -0
  2. package/lib/__lib__/QueryBuilderTesting.d.ts.map +1 -1
  3. package/lib/__lib__/QueryBuilderTesting.js +1 -0
  4. package/lib/__lib__/QueryBuilderTesting.js.map +1 -1
  5. package/lib/components/QueryBuilderConstantExpressionPanel.d.ts.map +1 -1
  6. package/lib/components/QueryBuilderConstantExpressionPanel.js +2 -1
  7. package/lib/components/QueryBuilderConstantExpressionPanel.js.map +1 -1
  8. package/lib/components/explorer/QueryBuilderExplorerPanel.d.ts +1 -0
  9. package/lib/components/explorer/QueryBuilderExplorerPanel.d.ts.map +1 -1
  10. package/lib/components/explorer/QueryBuilderExplorerPanel.js +87 -52
  11. package/lib/components/explorer/QueryBuilderExplorerPanel.js.map +1 -1
  12. package/lib/components/explorer/QueryBuilderPropertySearchPanel.d.ts +4 -0
  13. package/lib/components/explorer/QueryBuilderPropertySearchPanel.d.ts.map +1 -1
  14. package/lib/components/explorer/QueryBuilderPropertySearchPanel.js +172 -108
  15. package/lib/components/explorer/QueryBuilderPropertySearchPanel.js.map +1 -1
  16. package/lib/components/fetch-structure/QueryBuilderPostFilterPanel.d.ts.map +1 -1
  17. package/lib/components/fetch-structure/QueryBuilderPostFilterPanel.js +2 -1
  18. package/lib/components/fetch-structure/QueryBuilderPostFilterPanel.js.map +1 -1
  19. package/lib/components/fetch-structure/QueryBuilderTDSPanel.d.ts.map +1 -1
  20. package/lib/components/fetch-structure/QueryBuilderTDSPanel.js +29 -18
  21. package/lib/components/fetch-structure/QueryBuilderTDSPanel.js.map +1 -1
  22. package/lib/components/fetch-structure/QueryBuilderTDSWindowPanel.d.ts.map +1 -1
  23. package/lib/components/fetch-structure/QueryBuilderTDSWindowPanel.js +13 -4
  24. package/lib/components/fetch-structure/QueryBuilderTDSWindowPanel.js.map +1 -1
  25. package/lib/components/filter/QueryBuilderFilterPanel.d.ts.map +1 -1
  26. package/lib/components/filter/QueryBuilderFilterPanel.js +4 -3
  27. package/lib/components/filter/QueryBuilderFilterPanel.js.map +1 -1
  28. package/lib/components/result/QueryBuilderResultPanel.d.ts +12 -0
  29. package/lib/components/result/QueryBuilderResultPanel.d.ts.map +1 -1
  30. package/lib/components/result/QueryBuilderResultPanel.js +60 -8
  31. package/lib/components/result/QueryBuilderResultPanel.js.map +1 -1
  32. package/lib/components/shared/QueryBuilderFilterHelper.d.ts.map +1 -1
  33. package/lib/components/shared/QueryBuilderFilterHelper.js +3 -0
  34. package/lib/components/shared/QueryBuilderFilterHelper.js.map +1 -1
  35. package/lib/components/shared/QueryBuilderPropertyInfoTooltip.d.ts +11 -0
  36. package/lib/components/shared/QueryBuilderPropertyInfoTooltip.d.ts.map +1 -1
  37. package/lib/components/shared/QueryBuilderPropertyInfoTooltip.js +6 -3
  38. package/lib/components/shared/QueryBuilderPropertyInfoTooltip.js.map +1 -1
  39. package/lib/graph-manager/QueryBuilderConfig.d.ts +4 -0
  40. package/lib/graph-manager/QueryBuilderConfig.d.ts.map +1 -1
  41. package/lib/graph-manager/QueryBuilderConfig.js +5 -0
  42. package/lib/graph-manager/QueryBuilderConfig.js.map +1 -1
  43. package/lib/index.css +2 -2
  44. package/lib/index.css.map +1 -1
  45. package/lib/package.json +1 -1
  46. package/lib/stores/QueryBuilderConstantsState.d.ts +1 -0
  47. package/lib/stores/QueryBuilderConstantsState.d.ts.map +1 -1
  48. package/lib/stores/QueryBuilderConstantsState.js +6 -1
  49. package/lib/stores/QueryBuilderConstantsState.js.map +1 -1
  50. package/lib/stores/QueryBuilderResultState.d.ts +11 -3
  51. package/lib/stores/QueryBuilderResultState.d.ts.map +1 -1
  52. package/lib/stores/QueryBuilderResultState.js +47 -4
  53. package/lib/stores/QueryBuilderResultState.js.map +1 -1
  54. package/lib/stores/QueryBuilderValueSpecificationBuilderHelper.d.ts +4 -0
  55. package/lib/stores/QueryBuilderValueSpecificationBuilderHelper.d.ts.map +1 -1
  56. package/lib/stores/explorer/QueryBuilderExplorerState.d.ts +3 -1
  57. package/lib/stores/explorer/QueryBuilderExplorerState.d.ts.map +1 -1
  58. package/lib/stores/explorer/QueryBuilderExplorerState.js +63 -8
  59. package/lib/stores/explorer/QueryBuilderExplorerState.js.map +1 -1
  60. package/lib/stores/explorer/QueryBuilderFuzzySearchAdvancedConfigState.d.ts +24 -0
  61. package/lib/stores/explorer/QueryBuilderFuzzySearchAdvancedConfigState.d.ts.map +1 -0
  62. package/lib/stores/explorer/QueryBuilderFuzzySearchAdvancedConfigState.js +39 -0
  63. package/lib/stores/explorer/QueryBuilderFuzzySearchAdvancedConfigState.js.map +1 -0
  64. package/lib/stores/explorer/QueryBuilderPropertySearchState.d.ts +8 -4
  65. package/lib/stores/explorer/QueryBuilderPropertySearchState.d.ts.map +1 -1
  66. package/lib/stores/explorer/QueryBuilderPropertySearchState.js +204 -114
  67. package/lib/stores/explorer/QueryBuilderPropertySearchState.js.map +1 -1
  68. package/lib/stores/fetch-structure/tds/post-filter/QueryBuilderPostFilterState.d.ts.map +1 -1
  69. package/lib/stores/fetch-structure/tds/post-filter/QueryBuilderPostFilterState.js +8 -1
  70. package/lib/stores/fetch-structure/tds/post-filter/QueryBuilderPostFilterState.js.map +1 -1
  71. package/lib/stores/fetch-structure/tds/projection/QueryBuilderProjectionValueSpecificationBuilder.d.ts.map +1 -1
  72. package/lib/stores/fetch-structure/tds/projection/QueryBuilderProjectionValueSpecificationBuilder.js +12 -1
  73. package/lib/stores/fetch-structure/tds/projection/QueryBuilderProjectionValueSpecificationBuilder.js.map +1 -1
  74. package/lib/stores/filter/QueryBuilderFilterState.d.ts +8 -1
  75. package/lib/stores/filter/QueryBuilderFilterState.d.ts.map +1 -1
  76. package/lib/stores/filter/QueryBuilderFilterState.js +27 -10
  77. package/lib/stores/filter/QueryBuilderFilterState.js.map +1 -1
  78. package/package.json +8 -8
  79. package/src/__lib__/QueryBuilderTesting.ts +1 -0
  80. package/src/components/QueryBuilderConstantExpressionPanel.tsx +2 -1
  81. package/src/components/explorer/QueryBuilderExplorerPanel.tsx +220 -114
  82. package/src/components/explorer/QueryBuilderPropertySearchPanel.tsx +618 -388
  83. package/src/components/fetch-structure/QueryBuilderPostFilterPanel.tsx +5 -2
  84. package/src/components/fetch-structure/QueryBuilderTDSPanel.tsx +78 -44
  85. package/src/components/fetch-structure/QueryBuilderTDSWindowPanel.tsx +63 -10
  86. package/src/components/filter/QueryBuilderFilterPanel.tsx +4 -2
  87. package/src/components/result/QueryBuilderResultPanel.tsx +207 -20
  88. package/src/components/shared/QueryBuilderFilterHelper.ts +8 -0
  89. package/src/components/shared/QueryBuilderPropertyInfoTooltip.tsx +13 -3
  90. package/src/graph-manager/QueryBuilderConfig.ts +6 -0
  91. package/src/stores/QueryBuilderConstantsState.ts +16 -1
  92. package/src/stores/QueryBuilderResultState.ts +64 -10
  93. package/src/stores/QueryBuilderValueSpecificationBuilderHelper.ts +5 -0
  94. package/src/stores/explorer/QueryBuilderExplorerState.ts +92 -8
  95. package/src/stores/explorer/QueryBuilderFuzzySearchAdvancedConfigState.ts +46 -0
  96. package/src/stores/explorer/QueryBuilderPropertySearchState.ts +280 -142
  97. package/src/stores/fetch-structure/tds/post-filter/QueryBuilderPostFilterState.ts +8 -1
  98. package/src/stores/fetch-structure/tds/projection/QueryBuilderProjectionValueSpecificationBuilder.ts +15 -2
  99. package/src/stores/filter/QueryBuilderFilterState.ts +34 -11
  100. package/tsconfig.json +1 -0
@@ -14,7 +14,7 @@
14
14
  * limitations under the License.
15
15
  */
16
16
 
17
- import { forwardRef, useEffect, useRef, useState } from 'react';
17
+ import { forwardRef, useEffect, useMemo, useRef, useState } from 'react';
18
18
  import { observer } from 'mobx-react-lite';
19
19
  import {
20
20
  type TreeNodeContainerProps,
@@ -56,6 +56,8 @@ import {
56
56
  PanelHeaderActionItem,
57
57
  PanelHeaderActions,
58
58
  PanelHeader,
59
+ TimesIcon,
60
+ ClickAwayListener,
59
61
  } from '@finos/legend-art';
60
62
  import {
61
63
  type QueryBuilderExplorerTreeDragSource,
@@ -64,8 +66,6 @@ import {
64
66
  QueryBuilderExplorerTreeRootNodeData,
65
67
  QueryBuilderExplorerTreePropertyNodeData,
66
68
  QueryBuilderExplorerTreeSubTypeNodeData,
67
- getQueryBuilderPropertyNodeData,
68
- getQueryBuilderSubTypeNodeData,
69
69
  buildPropertyExpressionFromExplorerTreeNodeData,
70
70
  } from '../../stores/explorer/QueryBuilderExplorerState.js';
71
71
  import { useDrag } from 'react-dnd';
@@ -86,17 +86,16 @@ import {
86
86
  PRIMITIVE_TYPE,
87
87
  Enumeration,
88
88
  TYPE_CAST_TOKEN,
89
- getAllClassDerivedProperties,
90
89
  getMultiplicityDescription,
91
- getAllClassProperties,
92
- getAllOwnClassProperties,
93
90
  isElementDeprecated,
94
91
  } from '@finos/legend-graph';
95
92
  import { useApplicationStore } from '@finos/legend-application';
96
93
  import { QUERY_BUILDER_TEST_ID } from '../../__lib__/QueryBuilderTesting.js';
97
94
  import {
95
+ debounce,
98
96
  filterByType,
99
97
  guaranteeNonNullable,
98
+ isNonNullable,
100
99
  prettyCONSTName,
101
100
  } from '@finos/legend-shared';
102
101
  import { QueryBuilderPropertySearchPanel } from './QueryBuilderPropertySearchPanel.js';
@@ -105,6 +104,7 @@ import { QueryBuilderSimpleProjectionColumnState } from '../../stores/fetch-stru
105
104
  import { getClassPropertyIcon } from '@finos/legend-lego/graph-editor';
106
105
  import { QueryBuilderRootClassInfoTooltip } from '../shared/QueryBuilderRootClassInfoTooltip.js';
107
106
  import { QueryBuilderTelemetryHelper } from '../../__lib__/QueryBuilderTelemetryHelper.js';
107
+ import type { QueryBuilderPropertySearchState } from '../../stores/explorer/QueryBuilderPropertySearchState.js';
108
108
 
109
109
  export const checkForDeprecatedNode = (
110
110
  node: QueryBuilderExplorerTreeNodeData,
@@ -163,55 +163,81 @@ export const QueryBuilderSubclassInfoTooltip: React.FC<{
163
163
  multiplicity: Multiplicity;
164
164
  }> = (props) => {
165
165
  const { subclass, path, isMapped, children, placement, multiplicity } = props;
166
+
167
+ const [open, setIsOpen] = useState(false);
168
+
166
169
  return (
167
- <Tooltip
168
- arrow={true}
169
- {...(placement !== undefined ? { placement } : {})}
170
- classes={{
171
- tooltip: 'query-builder__tooltip',
172
- arrow: 'query-builder__tooltip__arrow',
173
- tooltipPlacementRight: 'query-builder__tooltip--right',
174
- }}
175
- TransitionProps={{
176
- // disable transition
177
- // NOTE: somehow, this is the only workaround we have, if for example
178
- // we set `appear = true`, the tooltip will jump out of position
179
- timeout: 0,
180
- }}
181
- title={
182
- <div className="query-builder__tooltip__content">
183
- <div className="query-builder__tooltip__item">
184
- <div className="query-builder__tooltip__item__label">Type</div>
185
- <div className="query-builder__tooltip__item__value">
186
- {subclass.path}
187
- </div>
188
- </div>
189
- <div className="query-builder__tooltip__item">
190
- <div className="query-builder__tooltip__item__label">Path</div>
191
- <div className="query-builder__tooltip__item__value">{path}</div>
192
- </div>
193
- <div className="query-builder__tooltip__item">
194
- <div className="query-builder__tooltip__item__label">
195
- Multiplicity
196
- </div>
197
- <div className="query-builder__tooltip__item__value">
198
- {getMultiplicityDescription(multiplicity)}
199
- </div>
200
- </div>
201
- <div className="query-builder__tooltip__item">
202
- <div className="query-builder__tooltip__item__label">Mapped</div>
203
- <div className="query-builder__tooltip__item__value">
204
- {isMapped ? 'Yes' : 'No'}
170
+ <ClickAwayListener
171
+ onClickAway={() => setIsOpen(false)}
172
+ mouseEvent="onMouseDown"
173
+ >
174
+ <div>
175
+ <Tooltip
176
+ arrow={true}
177
+ {...(placement !== undefined ? { placement } : {})}
178
+ classes={{
179
+ tooltip: 'query-builder__tooltip',
180
+ arrow: 'query-builder__tooltip__arrow',
181
+ tooltipPlacementRight: 'query-builder__tooltip--right',
182
+ }}
183
+ open={open}
184
+ onClose={() => setIsOpen(false)}
185
+ TransitionProps={{
186
+ // disable transition
187
+ // NOTE: somehow, this is the only workaround we have, if for example
188
+ // we set `appear = true`, the tooltip will jump out of position
189
+ timeout: 0,
190
+ }}
191
+ disableFocusListener={true}
192
+ disableHoverListener={true}
193
+ disableTouchListener={true}
194
+ title={
195
+ <div className="query-builder__tooltip__content">
196
+ <div className="query-builder__tooltip__item">
197
+ <div className="query-builder__tooltip__item__label">Type</div>
198
+ <div className="query-builder__tooltip__item__value">
199
+ {subclass.path}
200
+ </div>
201
+ </div>
202
+ <div className="query-builder__tooltip__item">
203
+ <div className="query-builder__tooltip__item__label">Path</div>
204
+ <div className="query-builder__tooltip__item__value">
205
+ {path}
206
+ </div>
207
+ </div>
208
+ <div className="query-builder__tooltip__item">
209
+ <div className="query-builder__tooltip__item__label">
210
+ Multiplicity
211
+ </div>
212
+ <div className="query-builder__tooltip__item__value">
213
+ {getMultiplicityDescription(multiplicity)}
214
+ </div>
215
+ </div>
216
+ <div className="query-builder__tooltip__item">
217
+ <div className="query-builder__tooltip__item__label">
218
+ Mapped
219
+ </div>
220
+ <div className="query-builder__tooltip__item__value">
221
+ {isMapped ? 'Yes' : 'No'}
222
+ </div>
223
+ </div>
224
+ <QueryBuilderTaggedValueInfoTooltip
225
+ taggedValues={subclass.taggedValues}
226
+ />
205
227
  </div>
228
+ }
229
+ >
230
+ <div
231
+ onClick={(event: React.MouseEvent) => {
232
+ setIsOpen(!open);
233
+ event.stopPropagation();
234
+ }}
235
+ >
236
+ {children}
206
237
  </div>
207
- <QueryBuilderTaggedValueInfoTooltip
208
- taggedValues={subclass.taggedValues}
209
- />
210
- </div>
211
- }
212
- >
213
- {children}
214
- </Tooltip>
238
+ </Tooltip>
239
+ </div>
240
+ </ClickAwayListener>
215
241
  );
216
242
  };
217
243
 
@@ -782,43 +808,9 @@ const QueryBuilderExplorerTree = observer(
782
808
  const treeData = explorerState.nonNullableTreeData;
783
809
  const onNodeSelect = (node: QueryBuilderExplorerTreeNodeData): void => {
784
810
  if (node.childrenIds.length) {
785
- node.isOpen = !node.isOpen;
786
- if (
787
- node.isOpen &&
788
- (node instanceof QueryBuilderExplorerTreePropertyNodeData ||
789
- node instanceof QueryBuilderExplorerTreeSubTypeNodeData) &&
790
- node.type instanceof Class
791
- ) {
792
- (node instanceof QueryBuilderExplorerTreeSubTypeNodeData
793
- ? getAllOwnClassProperties(node.type)
794
- : getAllClassProperties(node.type).concat(
795
- getAllClassDerivedProperties(node.type),
796
- )
797
- ).forEach((property) => {
798
- const propertyTreeNodeData = getQueryBuilderPropertyNodeData(
799
- property,
800
- node,
801
- guaranteeNonNullable(
802
- explorerState.mappingModelCoverageAnalysisResult,
803
- ),
804
- );
805
- if (propertyTreeNodeData) {
806
- treeData.nodes.set(propertyTreeNodeData.id, propertyTreeNodeData);
807
- }
808
- });
809
- node.type._subclasses.forEach((subclass) => {
810
- const subTypeTreeNodeData = getQueryBuilderSubTypeNodeData(
811
- subclass,
812
- node,
813
- guaranteeNonNullable(
814
- explorerState.mappingModelCoverageAnalysisResult,
815
- ),
816
- );
817
- treeData.nodes.set(subTypeTreeNodeData.id, subTypeTreeNodeData);
818
- });
819
- }
811
+ node.setIsOpen(!node.isOpen);
812
+ explorerState.generateOpenNodeChildren(node);
820
813
  }
821
- explorerState.refreshTree();
822
814
  };
823
815
  const getChildNodes = (
824
816
  node: QueryBuilderExplorerTreeNodeData,
@@ -860,19 +852,150 @@ const QueryBuilderExplorerTree = observer(
860
852
  },
861
853
  );
862
854
 
855
+ export const QUERY_BUILDER_EXPLORER_SEARCH_INPUT_NAME =
856
+ 'query-builder-explorer-search-input';
857
+
858
+ const QUERY_BUILDER_PROPERTY_SEARCH_MIN_SEARCH_LENGTH = 2;
859
+
860
+ const QueryBuilderExplorerSearchInput = observer(
861
+ forwardRef<
862
+ HTMLInputElement,
863
+ { propertySearchState: QueryBuilderPropertySearchState }
864
+ >(function QueryBuilderExplorerSearchInput(props, ref) {
865
+ const { propertySearchState } = props;
866
+
867
+ // initialize search state on mount
868
+ useEffect(() => {
869
+ if (
870
+ !propertySearchState.initializationState.hasSucceeded &&
871
+ !propertySearchState.initializationState.isInProgress &&
872
+ isNonNullable(
873
+ propertySearchState.queryBuilderState.explorerState.treeData,
874
+ )
875
+ ) {
876
+ propertySearchState
877
+ .initialize()
878
+ .catch(
879
+ propertySearchState.queryBuilderState.applicationStore
880
+ .alertUnhandledError,
881
+ );
882
+ }
883
+ }, [
884
+ propertySearchState,
885
+ propertySearchState.initializationState,
886
+ propertySearchState.queryBuilderState.explorerState.treeData,
887
+ ]);
888
+
889
+ // search text
890
+ const debouncedSearchProperty = useMemo(
891
+ () => debounce(() => propertySearchState.search(), 100),
892
+ [propertySearchState],
893
+ );
894
+
895
+ const onSearchPropertyTextChange: React.ChangeEventHandler<
896
+ HTMLInputElement
897
+ > = (event) => {
898
+ (async () => {
899
+ propertySearchState.setSearchText(event.target.value);
900
+ if (
901
+ event.target.value.length >=
902
+ QUERY_BUILDER_PROPERTY_SEARCH_MIN_SEARCH_LENGTH
903
+ ) {
904
+ if (
905
+ propertySearchState.queryBuilderState.explorerState.treeData &&
906
+ !propertySearchState.isSearchPanelOpen
907
+ ) {
908
+ propertySearchState.setIsSearchPanelOpen(true);
909
+ if (
910
+ !propertySearchState.initializationState.hasSucceeded &&
911
+ !propertySearchState.initializationState.isInProgress
912
+ ) {
913
+ await propertySearchState.initialize();
914
+ }
915
+ }
916
+ await debouncedSearchProperty();
917
+ } else {
918
+ propertySearchState.setIsSearchPanelOpen(false);
919
+ }
920
+ })().catch(
921
+ propertySearchState.queryBuilderState.applicationStore
922
+ .alertUnhandledError,
923
+ );
924
+ };
925
+
926
+ // search actions
927
+ const clearSearch = (): void => {
928
+ propertySearchState.resetSearch();
929
+ };
930
+
931
+ return (
932
+ <div className="query-builder__explorer__property-search__input__container">
933
+ <input
934
+ ref={ref}
935
+ name={QUERY_BUILDER_EXPLORER_SEARCH_INPUT_NAME}
936
+ className={clsx(
937
+ 'query-builder__explorer__property-search__input input--dark',
938
+ {
939
+ 'query-builder__explorer__property-search__input--searching':
940
+ propertySearchState.searchText,
941
+ },
942
+ )}
943
+ spellCheck={false}
944
+ onChange={onSearchPropertyTextChange}
945
+ onKeyDown={(event): void => {
946
+ if (event.key === 'Escape') {
947
+ clearSearch();
948
+ propertySearchState.setIsSearchPanelOpen(false);
949
+ }
950
+ }}
951
+ value={propertySearchState.searchText}
952
+ placeholder="One or more terms, ESC to clear"
953
+ />
954
+ {propertySearchState.searchText.length >=
955
+ QUERY_BUILDER_PROPERTY_SEARCH_MIN_SEARCH_LENGTH && (
956
+ <div className="query-builder__explorer__property-search__input__search__count">
957
+ {propertySearchState.filteredSearchResults.length +
958
+ (propertySearchState.isOverSearchLimit &&
959
+ propertySearchState.filteredSearchResults.length !== 0
960
+ ? '+'
961
+ : '')}
962
+ </div>
963
+ )}
964
+ {!propertySearchState.searchText ? (
965
+ <>
966
+ <div className="query-builder__explorer__property-search__input__search__icon">
967
+ <SearchIcon />
968
+ </div>
969
+ </>
970
+ ) : (
971
+ <button
972
+ className="query-builder__explorer__property-search__input__clear-btn"
973
+ tabIndex={-1}
974
+ onClick={clearSearch}
975
+ title="Clear"
976
+ >
977
+ <TimesIcon />
978
+ </button>
979
+ )}
980
+ </div>
981
+ );
982
+ }),
983
+ );
984
+
863
985
  export const QueryBuilderExplorerPanel = observer(
864
986
  (props: { queryBuilderState: QueryBuilderState }) => {
865
987
  const { queryBuilderState } = props;
866
- const searchButtonRef = useRef<HTMLButtonElement>(null);
988
+ const searchInputRef = useRef<HTMLInputElement>(null);
867
989
  const explorerState = queryBuilderState.explorerState;
868
990
  const propertySearchPanelState = explorerState.propertySearchState;
869
991
  const applicationStore = useApplicationStore();
870
992
  const collapseTree = (): void => {
871
993
  if (explorerState.treeData) {
872
994
  Array.from(explorerState.treeData.nodes.values()).forEach((node) => {
873
- node.isOpen = false;
995
+ if (!(node instanceof QueryBuilderExplorerTreeRootNodeData)) {
996
+ node.setIsOpen(false);
997
+ }
874
998
  });
875
- explorerState.refreshTree();
876
999
  }
877
1000
  };
878
1001
  const toggleShowUnmappedProperties = (): void => {
@@ -891,16 +1014,6 @@ export const QueryBuilderExplorerPanel = observer(
891
1014
  explorerState.setHighlightUsedProperties(
892
1015
  !explorerState.highlightUsedProperties,
893
1016
  );
894
- const togglePropertySearch = (): void => {
895
- if (explorerState.treeData) {
896
- if (!propertySearchPanelState.isSearchPanelOpen) {
897
- propertySearchPanelState.setIsSearchPanelOpen(true);
898
- propertySearchPanelState.initialize();
899
- } else {
900
- propertySearchPanelState.setIsSearchPanelOpen(false);
901
- }
902
- }
903
- };
904
1017
 
905
1018
  useEffect(() => {
906
1019
  flowResult(explorerState.analyzeMappingModelCoverage()).catch(
@@ -919,19 +1032,11 @@ export const QueryBuilderExplorerPanel = observer(
919
1032
  })}
920
1033
  >
921
1034
  <PanelHeader title="explorer">
1035
+ <QueryBuilderExplorerSearchInput
1036
+ propertySearchState={propertySearchPanelState}
1037
+ ref={searchInputRef}
1038
+ />
922
1039
  <PanelHeaderActions>
923
- <button
924
- ref={searchButtonRef}
925
- className={clsx('panel__header__action', {
926
- 'query-builder__explorer__header__action--active':
927
- propertySearchPanelState.isSearchPanelOpen,
928
- })}
929
- onClick={togglePropertySearch}
930
- tabIndex={-1}
931
- title="Toggle property search"
932
- >
933
- <SearchIcon />
934
- </button>
935
1040
  <PanelHeaderActionItem onClick={collapseTree} title="Collapse Tree">
936
1041
  <CompressIcon />
937
1042
  </PanelHeaderActionItem>
@@ -984,7 +1089,8 @@ export const QueryBuilderExplorerPanel = observer(
984
1089
  {propertySearchPanelState.isSearchPanelOpen && (
985
1090
  <QueryBuilderPropertySearchPanel
986
1091
  queryBuilderState={queryBuilderState}
987
- triggerElement={searchButtonRef.current}
1092
+ triggerElement={searchInputRef.current}
1093
+ clearSearch={() => propertySearchPanelState.resetSearch()}
988
1094
  />
989
1095
  )}
990
1096
  </PanelHeader>