module Gargantext.Components.GraphExplorer.Topbar.Search ( Props, nodeSearchControl ) where import Prelude import DOM.Simple.Console (log2) import Data.Foldable (foldl, intercalate) import Data.Sequence as Seq import Data.Set as Set import Effect (Effect) import Gargantext.Components.Bootstrap as B import Gargantext.Components.InputWithAutocomplete (inputWithAutocomplete) import Gargantext.Hooks.Sigmax.Types as SigmaxT import Gargantext.Utils (queryMatchesLabel) import Gargantext.Utils.Reactix as R2 import Reactix as R import Reactix.DOM.HTML as H import Toestand as T here :: R2.Here here = R2.here "Gargantext.Components.GraphExplorer.Topbar.Search" type Props = ( graph :: SigmaxT.SGraph , multiSelectEnabled :: T.Box Boolean , selectedNodeIds :: T.Box SigmaxT.NodeIds , className :: String ) -- | Whether a node matches a search string -- Searches given node and matches it's label or any of the children's labels. nodeMatchesSearch :: String -> Record SigmaxT.Node -> Boolean nodeMatchesSearch s n@{ children } = foldl (\_ childLabel -> queryMatchesLabel s childLabel) initial children where initial = queryMatchesLabel s n.label searchNodes :: String -> Seq.Seq (Record SigmaxT.Node) -> Seq.Seq (Record SigmaxT.Node) searchNodes "" _ = Seq.empty searchNodes s nodes = Seq.filter (nodeMatchesSearch s) nodes nodeSearchControl :: R2.Leaf Props nodeSearchControl = R2.leaf nodeSearchControlCpt nodeSearchControlCpt :: R.Component Props nodeSearchControlCpt = here.component "nodeSearchControl" cpt where cpt props@{ graph, multiSelectEnabled, selectedNodeIds } _ = do search <- T.useBox "" search' <- T.useLive T.unequal search multiSelectEnabled' <- T.useLive T.unequal multiSelectEnabled let doSearch s = triggerSearch graph s multiSelectEnabled' selectedNodeIds pure $ H.form { className: intercalate " " [ "graph-node-search" , props.className ] } [ inputWithAutocomplete { autocompleteSearch: autocompleteSearch graph , onAutocompleteClick: doSearch , onEnterPress: doSearch , classes: "" , state: search } , B.button { callback: \_ -> doSearch search' , type: "submit" , className: "graph-node-search__submit" } [ B.icon { name: "search"} ] ] autocompleteSearch :: SigmaxT.SGraph -> String -> Array String autocompleteSearch graph s = Seq.toUnfoldable $ (_.label) <$> searchNodes s nodes where nodes = SigmaxT.graphNodes graph triggerSearch :: SigmaxT.SGraph -> String -> Boolean -> T.Box SigmaxT.NodeIds -> Effect Unit triggerSearch graph search multiSelectEnabled selectedNodeIds = do let graphNodes = SigmaxT.graphNodes graph let matching = Set.fromFoldable $ (_.id) <$> searchNodes search graphNodes log2 "[triggerSearch] search" search T.modify_ (\nodes -> Set.union matching $ if multiSelectEnabled then nodes else SigmaxT.emptyNodeIds) selectedNodeIds