@@ -21,13 +21,19 @@ import { debounce } from 'lodash';
2121import { useCallback , useEffect , useMemo , useRef , useState } from 'react' ;
2222import { useTranslation } from 'react-i18next' ;
2323import { useNavigate } from 'react-router-dom' ;
24+ import { ReactComponent as IconSuggestionsActive } from '../../../assets/svg/ic-suggestions-active.svg' ;
25+ import { ReactComponent as IconSuggestionsBlue } from '../../../assets/svg/ic-suggestions-blue.svg' ;
2426import { INITIAL_PAGING_VALUE } from '../../../constants/constants' ;
2527import { SearchIndex } from '../../../enums/search.enum' ;
2628import { DataProduct } from '../../../generated/entity/domains/dataProduct' ;
2729import { Domain } from '../../../generated/entity/domains/domain' ;
2830import { useMarketplaceRecentSearches } from '../../../hooks/useMarketplaceRecentSearches' ;
2931import { useMarketplaceStore } from '../../../hooks/useMarketplaceStore' ;
30- import { searchQuery } from '../../../rest/searchAPI' ;
32+ import {
33+ getNLPEnabledStatus ,
34+ nlqSearch ,
35+ searchQuery ,
36+ } from '../../../rest/searchAPI' ;
3137import { getDataProductIconByUrl } from '../../../utils/DataProductUtils' ;
3238import { getDomainIcon } from '../../../utils/DomainUtils' ;
3339import { getDomainDetailsPath } from '../../../utils/RouterUtils' ;
@@ -40,6 +46,8 @@ const MarketplaceSearchBar = ({ isEditView }: { isEditView?: boolean }) => {
4046 const { t } = useTranslation ( ) ;
4147 const navigate = useNavigate ( ) ;
4248 const { dataProductBasePath } = useMarketplaceStore ( ) ;
49+ const [ isNLPEnabled , setIsNLPEnabled ] = useState ( false ) ;
50+ const [ isNLQActive , setIsNLQActive ] = useState ( false ) ;
4351 const [ searchValue , setSearchValue ] = useState ( '' ) ;
4452 const [ isOpen , setIsOpen ] = useState ( false ) ;
4553 const [ dataProducts , setDataProducts ] = useState < DataProduct [ ] > ( [ ] ) ;
@@ -48,41 +56,73 @@ const MarketplaceSearchBar = ({ isEditView }: { isEditView?: boolean }) => {
4856 const containerRef = useRef < HTMLDivElement > ( null ) ;
4957 const { addSearch } = useMarketplaceRecentSearches ( ) ;
5058
51- const fetchResults = useCallback ( async ( query : string ) => {
52- if ( ! query . trim ( ) ) {
53- setDataProducts ( [ ] ) ;
54- setDomains ( [ ] ) ;
59+ useEffect ( ( ) => {
60+ getNLPEnabledStatus ( )
61+ . then ( setIsNLPEnabled )
62+ . catch ( ( ) => setIsNLPEnabled ( false ) ) ;
63+ } , [ ] ) ;
5564
56- return ;
57- }
58- setIsSearching ( true ) ;
59- try {
60- const [ dpRes , domainRes ] = await Promise . all ( [
61- searchQuery ( {
62- query,
63- pageNumber : INITIAL_PAGING_VALUE ,
64- pageSize : PAGE_SIZE ,
65- searchIndex : SearchIndex . DATA_PRODUCT ,
66- } ) ,
67- searchQuery ( {
68- query,
69- pageNumber : INITIAL_PAGING_VALUE ,
70- pageSize : PAGE_SIZE ,
71- searchIndex : SearchIndex . DOMAIN ,
72- } ) ,
73- ] ) ;
65+ const fetchResults = useCallback (
66+ async ( query : string ) => {
67+ if ( ! query . trim ( ) ) {
68+ setDataProducts ( [ ] ) ;
69+ setDomains ( [ ] ) ;
7470
75- setDataProducts (
76- dpRes . hits . hits . map ( ( hit ) => hit . _source ) as DataProduct [ ]
77- ) ;
78- setDomains ( domainRes . hits . hits . map ( ( hit ) => hit . _source ) as Domain [ ] ) ;
79- } catch {
80- setDataProducts ( [ ] ) ;
81- setDomains ( [ ] ) ;
82- } finally {
83- setIsSearching ( false ) ;
84- }
85- } , [ ] ) ;
71+ return ;
72+ }
73+ setIsSearching ( true ) ;
74+ try {
75+ if ( isNLPEnabled && isNLQActive ) {
76+ const res = await nlqSearch ( {
77+ query,
78+ pageNumber : INITIAL_PAGING_VALUE ,
79+ pageSize : PAGE_SIZE * 2 ,
80+ searchIndex : SearchIndex . MARKETPLACE ,
81+ } ) ;
82+
83+ const hits = res . hits . hits ;
84+ setDataProducts (
85+ hits
86+ . filter ( ( h ) => h . _source . entityType === SearchIndex . DATA_PRODUCT )
87+ . slice ( 0 , PAGE_SIZE )
88+ . map ( ( h ) => h . _source as unknown as DataProduct )
89+ ) ;
90+ setDomains (
91+ hits
92+ . filter ( ( h ) => h . _source . entityType === SearchIndex . DOMAIN )
93+ . slice ( 0 , PAGE_SIZE )
94+ . map ( ( h ) => h . _source as unknown as Domain )
95+ ) ;
96+ } else {
97+ const [ dpRes , domainRes ] = await Promise . all ( [
98+ searchQuery ( {
99+ query,
100+ pageNumber : INITIAL_PAGING_VALUE ,
101+ pageSize : PAGE_SIZE ,
102+ searchIndex : SearchIndex . DATA_PRODUCT ,
103+ } ) ,
104+ searchQuery ( {
105+ query,
106+ pageNumber : INITIAL_PAGING_VALUE ,
107+ pageSize : PAGE_SIZE ,
108+ searchIndex : SearchIndex . DOMAIN ,
109+ } ) ,
110+ ] ) ;
111+
112+ setDataProducts (
113+ dpRes . hits . hits . map ( ( hit ) => hit . _source ) as DataProduct [ ]
114+ ) ;
115+ setDomains ( domainRes . hits . hits . map ( ( hit ) => hit . _source ) as Domain [ ] ) ;
116+ }
117+ } catch {
118+ setDataProducts ( [ ] ) ;
119+ setDomains ( [ ] ) ;
120+ } finally {
121+ setIsSearching ( false ) ;
122+ }
123+ } ,
124+ [ isNLPEnabled , isNLQActive ]
125+ ) ;
86126
87127 const debouncedFetch = useMemo (
88128 ( ) => debounce ( fetchResults , 400 ) ,
@@ -248,27 +288,50 @@ const MarketplaceSearchBar = ({ isEditView }: { isEditView?: boolean }) => {
248288 className = "marketplace-search-bar"
249289 data-testid = "marketplace-search-bar"
250290 ref = { containerRef } >
251- < Input
252- autoComplete = "off"
253- data-testid = "marketplace-search-input"
254- fontSize = "sm"
255- icon = { SearchLg }
256- iconClassName = "tw:!size-4"
257- inputClassName = "tw:!pl-9"
258- isDisabled = { isEditView }
259- placeholder = { t ( 'label.search-for-type' , {
260- type :
261- t ( 'label.data-product-plural' ) + ', ' + t ( 'label.domain-plural' ) ,
262- } ) }
263- value = { searchValue }
264- wrapperClassName = "marketplace-search-input tw:!rounded-xl tw:!items-center tw:!py-1"
265- onChange = { ( value ) => handleChange ( value ) }
266- onKeyDown = { ( e ) => {
267- if ( e . key === 'Enter' ) {
268- handleSearch ( searchValue ) ;
269- }
270- } }
271- />
291+ < div className = "tw:relative" >
292+ < div className = "tw:absolute tw:left-3 tw:top-1/2 tw:-translate-y-1/2 tw:z-10 tw:flex tw:items-center" >
293+ { isNLPEnabled ? (
294+ < button
295+ className = { `marketplace-nlq-button${
296+ isNLQActive ? ' active' : ''
297+ } `}
298+ data-testid = "marketplace-nlq-toggle"
299+ title = {
300+ isNLQActive
301+ ? t ( 'message.natural-language-search-active' )
302+ : t ( 'label.use-natural-language-search' )
303+ }
304+ onClick = { ( ) => setIsNLQActive ( ( prev ) => ! prev ) } >
305+ { isNLQActive ? (
306+ < IconSuggestionsActive />
307+ ) : (
308+ < IconSuggestionsBlue />
309+ ) }
310+ </ button >
311+ ) : (
312+ < SearchLg className = "tw:size-4 tw:text-text-tertiary" />
313+ ) }
314+ </ div >
315+ < Input
316+ autoComplete = "off"
317+ data-testid = "marketplace-search-input"
318+ fontSize = "sm"
319+ inputClassName = "tw:!pl-11"
320+ isDisabled = { isEditView }
321+ placeholder = { t ( 'label.search-for-type' , {
322+ type :
323+ t ( 'label.data-product-plural' ) + ', ' + t ( 'label.domain-plural' ) ,
324+ } ) }
325+ value = { searchValue }
326+ wrapperClassName = "marketplace-search-input tw:!rounded-xl tw:!items-center tw:!py-1"
327+ onChange = { ( value ) => handleChange ( value ) }
328+ onKeyDown = { ( e ) => {
329+ if ( e . key === 'Enter' ) {
330+ handleSearch ( searchValue ) ;
331+ }
332+ } }
333+ />
334+ </ div >
272335 < SelectPopover
273336 isNonModal
274337 className = "!tw:max-h-[400px]"
0 commit comments