@finos/legend-query-builder 4.14.68 → 4.14.70

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 (105) 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/explorer/QueryBuilderExplorerPanel.d.ts +1 -0
  6. package/lib/components/explorer/QueryBuilderExplorerPanel.d.ts.map +1 -1
  7. package/lib/components/explorer/QueryBuilderExplorerPanel.js +95 -53
  8. package/lib/components/explorer/QueryBuilderExplorerPanel.js.map +1 -1
  9. package/lib/components/explorer/QueryBuilderPropertySearchPanel.d.ts +4 -0
  10. package/lib/components/explorer/QueryBuilderPropertySearchPanel.d.ts.map +1 -1
  11. package/lib/components/explorer/QueryBuilderPropertySearchPanel.js +172 -108
  12. package/lib/components/explorer/QueryBuilderPropertySearchPanel.js.map +1 -1
  13. package/lib/components/fetch-structure/QueryBuilderPostFilterPanel.d.ts.map +1 -1
  14. package/lib/components/fetch-structure/QueryBuilderPostFilterPanel.js +2 -1
  15. package/lib/components/fetch-structure/QueryBuilderPostFilterPanel.js.map +1 -1
  16. package/lib/components/fetch-structure/QueryBuilderTDSPanel.d.ts.map +1 -1
  17. package/lib/components/fetch-structure/QueryBuilderTDSPanel.js +29 -18
  18. package/lib/components/fetch-structure/QueryBuilderTDSPanel.js.map +1 -1
  19. package/lib/components/fetch-structure/QueryBuilderTDSWindowPanel.d.ts.map +1 -1
  20. package/lib/components/fetch-structure/QueryBuilderTDSWindowPanel.js +13 -4
  21. package/lib/components/fetch-structure/QueryBuilderTDSWindowPanel.js.map +1 -1
  22. package/lib/components/filter/QueryBuilderFilterPanel.d.ts.map +1 -1
  23. package/lib/components/filter/QueryBuilderFilterPanel.js +4 -3
  24. package/lib/components/filter/QueryBuilderFilterPanel.js.map +1 -1
  25. package/lib/components/result/QueryBuilderResultPanel.d.ts +12 -0
  26. package/lib/components/result/QueryBuilderResultPanel.d.ts.map +1 -1
  27. package/lib/components/result/QueryBuilderResultPanel.js +60 -8
  28. package/lib/components/result/QueryBuilderResultPanel.js.map +1 -1
  29. package/lib/components/result/tds/QueryBuilderTDSGridResult.d.ts.map +1 -1
  30. package/lib/components/result/tds/QueryBuilderTDSGridResult.js +47 -28
  31. package/lib/components/result/tds/QueryBuilderTDSGridResult.js.map +1 -1
  32. package/lib/components/result/tds/QueryBuilderTDSSimpleGridResult.d.ts +1 -0
  33. package/lib/components/result/tds/QueryBuilderTDSSimpleGridResult.d.ts.map +1 -1
  34. package/lib/components/result/tds/QueryBuilderTDSSimpleGridResult.js +34 -1
  35. package/lib/components/result/tds/QueryBuilderTDSSimpleGridResult.js.map +1 -1
  36. package/lib/components/shared/QueryBuilderFilterHelper.d.ts.map +1 -1
  37. package/lib/components/shared/QueryBuilderFilterHelper.js +3 -0
  38. package/lib/components/shared/QueryBuilderFilterHelper.js.map +1 -1
  39. package/lib/components/shared/QueryBuilderPropertyInfoTooltip.d.ts +11 -0
  40. package/lib/components/shared/QueryBuilderPropertyInfoTooltip.d.ts.map +1 -1
  41. package/lib/components/shared/QueryBuilderPropertyInfoTooltip.js +6 -3
  42. package/lib/components/shared/QueryBuilderPropertyInfoTooltip.js.map +1 -1
  43. package/lib/graph-manager/QueryBuilderConfig.d.ts +4 -0
  44. package/lib/graph-manager/QueryBuilderConfig.d.ts.map +1 -1
  45. package/lib/graph-manager/QueryBuilderConfig.js +5 -0
  46. package/lib/graph-manager/QueryBuilderConfig.js.map +1 -1
  47. package/lib/index.css +2 -2
  48. package/lib/index.css.map +1 -1
  49. package/lib/package.json +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 +5 -1
  57. package/lib/stores/explorer/QueryBuilderExplorerState.d.ts.map +1 -1
  58. package/lib/stores/explorer/QueryBuilderExplorerState.js +80 -10
  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/lib/stores/shared/ValueSpecificationEditorHelper.d.ts +1 -0
  79. package/lib/stores/shared/ValueSpecificationEditorHelper.d.ts.map +1 -1
  80. package/lib/stores/shared/ValueSpecificationEditorHelper.js +6 -2
  81. package/lib/stores/shared/ValueSpecificationEditorHelper.js.map +1 -1
  82. package/package.json +9 -9
  83. package/src/__lib__/QueryBuilderTesting.ts +1 -0
  84. package/src/components/explorer/QueryBuilderExplorerPanel.tsx +228 -115
  85. package/src/components/explorer/QueryBuilderPropertySearchPanel.tsx +618 -388
  86. package/src/components/fetch-structure/QueryBuilderPostFilterPanel.tsx +5 -2
  87. package/src/components/fetch-structure/QueryBuilderTDSPanel.tsx +78 -44
  88. package/src/components/fetch-structure/QueryBuilderTDSWindowPanel.tsx +63 -10
  89. package/src/components/filter/QueryBuilderFilterPanel.tsx +4 -2
  90. package/src/components/result/QueryBuilderResultPanel.tsx +207 -20
  91. package/src/components/result/tds/QueryBuilderTDSGridResult.tsx +57 -38
  92. package/src/components/result/tds/QueryBuilderTDSSimpleGridResult.tsx +43 -0
  93. package/src/components/shared/QueryBuilderFilterHelper.ts +8 -0
  94. package/src/components/shared/QueryBuilderPropertyInfoTooltip.tsx +13 -3
  95. package/src/graph-manager/QueryBuilderConfig.ts +6 -0
  96. package/src/stores/QueryBuilderResultState.ts +64 -10
  97. package/src/stores/QueryBuilderValueSpecificationBuilderHelper.ts +5 -0
  98. package/src/stores/explorer/QueryBuilderExplorerState.ts +112 -8
  99. package/src/stores/explorer/QueryBuilderFuzzySearchAdvancedConfigState.ts +46 -0
  100. package/src/stores/explorer/QueryBuilderPropertySearchState.ts +280 -142
  101. package/src/stores/fetch-structure/tds/post-filter/QueryBuilderPostFilterState.ts +8 -1
  102. package/src/stores/fetch-structure/tds/projection/QueryBuilderProjectionValueSpecificationBuilder.ts +15 -2
  103. package/src/stores/filter/QueryBuilderFilterState.ts +34 -11
  104. package/src/stores/shared/ValueSpecificationEditorHelper.ts +9 -1
  105. 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
 
@@ -220,7 +246,14 @@ const QueryBuilderExplorerPreviewDataModal = observer(
220
246
  const { queryBuilderState } = props;
221
247
  const applicationStore = queryBuilderState.applicationStore;
222
248
  const previewDataState = queryBuilderState.explorerState.previewDataState;
223
- const close = (): void => previewDataState.setPreviewData(undefined);
249
+ const close = (): void => {
250
+ if (previewDataState.previewDataAbortController) {
251
+ previewDataState.previewDataAbortController.abort();
252
+ previewDataState.setPreviewDataAbortController(undefined);
253
+ }
254
+ previewDataState.setIsGeneratingPreviewData(false);
255
+ previewDataState.setPreviewData(undefined);
256
+ };
224
257
 
225
258
  return (
226
259
  <Dialog
@@ -775,43 +808,9 @@ const QueryBuilderExplorerTree = observer(
775
808
  const treeData = explorerState.nonNullableTreeData;
776
809
  const onNodeSelect = (node: QueryBuilderExplorerTreeNodeData): void => {
777
810
  if (node.childrenIds.length) {
778
- node.isOpen = !node.isOpen;
779
- if (
780
- node.isOpen &&
781
- (node instanceof QueryBuilderExplorerTreePropertyNodeData ||
782
- node instanceof QueryBuilderExplorerTreeSubTypeNodeData) &&
783
- node.type instanceof Class
784
- ) {
785
- (node instanceof QueryBuilderExplorerTreeSubTypeNodeData
786
- ? getAllOwnClassProperties(node.type)
787
- : getAllClassProperties(node.type).concat(
788
- getAllClassDerivedProperties(node.type),
789
- )
790
- ).forEach((property) => {
791
- const propertyTreeNodeData = getQueryBuilderPropertyNodeData(
792
- property,
793
- node,
794
- guaranteeNonNullable(
795
- explorerState.mappingModelCoverageAnalysisResult,
796
- ),
797
- );
798
- if (propertyTreeNodeData) {
799
- treeData.nodes.set(propertyTreeNodeData.id, propertyTreeNodeData);
800
- }
801
- });
802
- node.type._subclasses.forEach((subclass) => {
803
- const subTypeTreeNodeData = getQueryBuilderSubTypeNodeData(
804
- subclass,
805
- node,
806
- guaranteeNonNullable(
807
- explorerState.mappingModelCoverageAnalysisResult,
808
- ),
809
- );
810
- treeData.nodes.set(subTypeTreeNodeData.id, subTypeTreeNodeData);
811
- });
812
- }
811
+ node.setIsOpen(!node.isOpen);
812
+ explorerState.generateOpenNodeChildren(node);
813
813
  }
814
- explorerState.refreshTree();
815
814
  };
816
815
  const getChildNodes = (
817
816
  node: QueryBuilderExplorerTreeNodeData,
@@ -853,19 +852,150 @@ const QueryBuilderExplorerTree = observer(
853
852
  },
854
853
  );
855
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
+
856
985
  export const QueryBuilderExplorerPanel = observer(
857
986
  (props: { queryBuilderState: QueryBuilderState }) => {
858
987
  const { queryBuilderState } = props;
859
- const searchButtonRef = useRef<HTMLButtonElement>(null);
988
+ const searchInputRef = useRef<HTMLInputElement>(null);
860
989
  const explorerState = queryBuilderState.explorerState;
861
990
  const propertySearchPanelState = explorerState.propertySearchState;
862
991
  const applicationStore = useApplicationStore();
863
992
  const collapseTree = (): void => {
864
993
  if (explorerState.treeData) {
865
994
  Array.from(explorerState.treeData.nodes.values()).forEach((node) => {
866
- node.isOpen = false;
995
+ if (!(node instanceof QueryBuilderExplorerTreeRootNodeData)) {
996
+ node.setIsOpen(false);
997
+ }
867
998
  });
868
- explorerState.refreshTree();
869
999
  }
870
1000
  };
871
1001
  const toggleShowUnmappedProperties = (): void => {
@@ -884,16 +1014,6 @@ export const QueryBuilderExplorerPanel = observer(
884
1014
  explorerState.setHighlightUsedProperties(
885
1015
  !explorerState.highlightUsedProperties,
886
1016
  );
887
- const togglePropertySearch = (): void => {
888
- if (explorerState.treeData) {
889
- if (!propertySearchPanelState.isSearchPanelOpen) {
890
- propertySearchPanelState.setIsSearchPanelOpen(true);
891
- propertySearchPanelState.initialize();
892
- } else {
893
- propertySearchPanelState.setIsSearchPanelOpen(false);
894
- }
895
- }
896
- };
897
1017
 
898
1018
  useEffect(() => {
899
1019
  flowResult(explorerState.analyzeMappingModelCoverage()).catch(
@@ -912,19 +1032,11 @@ export const QueryBuilderExplorerPanel = observer(
912
1032
  })}
913
1033
  >
914
1034
  <PanelHeader title="explorer">
1035
+ <QueryBuilderExplorerSearchInput
1036
+ propertySearchState={propertySearchPanelState}
1037
+ ref={searchInputRef}
1038
+ />
915
1039
  <PanelHeaderActions>
916
- <button
917
- ref={searchButtonRef}
918
- className={clsx('panel__header__action', {
919
- 'query-builder__explorer__header__action--active':
920
- propertySearchPanelState.isSearchPanelOpen,
921
- })}
922
- onClick={togglePropertySearch}
923
- tabIndex={-1}
924
- title="Toggle property search"
925
- >
926
- <SearchIcon />
927
- </button>
928
1040
  <PanelHeaderActionItem onClick={collapseTree} title="Collapse Tree">
929
1041
  <CompressIcon />
930
1042
  </PanelHeaderActionItem>
@@ -977,7 +1089,8 @@ export const QueryBuilderExplorerPanel = observer(
977
1089
  {propertySearchPanelState.isSearchPanelOpen && (
978
1090
  <QueryBuilderPropertySearchPanel
979
1091
  queryBuilderState={queryBuilderState}
980
- triggerElement={searchButtonRef.current}
1092
+ triggerElement={searchInputRef.current}
1093
+ clearSearch={() => propertySearchPanelState.resetSearch()}
981
1094
  />
982
1095
  )}
983
1096
  </PanelHeader>