Commit de7cc92e authored by Przemyslaw Kaminski's avatar Przemyslaw Kaminski

[Graph] autocomplete input & implement it in graph search

parent 98d17712
......@@ -15,9 +15,9 @@
}
#graph-explorer .graph-tree {
position: absolute;
top: 150px;
max-height: 600px;
overflow-y: scroll;
top: 150px;
z-index: 1;
}
#graph-explorer #graph-view {
......@@ -25,9 +25,9 @@
}
#graph-explorer #sp-container {
position: absolute;
top: 150px;
max-height: 600px;
overflow-y: scroll;
top: 150px;
z-index: 1;
left: 70%;
border: 1px white solid;
......@@ -50,4 +50,13 @@
z-index: 1;
}
.input-with-autocomplete .completions {
position: absolute;
max-height: 300px;
overflow-y: scroll;
width: 300px;
top: 50px;
z-index: 5;
}
/*# sourceMappingURL=Graph.css.map */
@mixin sidePanelCommon
position: absolute
top: 150px
max-height: 600px
overflow-y: scroll
top: 150px
z-index: 1
#graph-explorer
......@@ -48,3 +48,12 @@
#tree
position: absolute
z-index: 1
.input-with-autocomplete
.completions
position: absolute
max-height: 300px
overflow-y: scroll
width: 300px
top: 50px
z-index: 5
......@@ -16,9 +16,9 @@ import Data.Maybe (Maybe(..), maybe)
import Data.Set (Set)
import Data.Set as Set
import Data.Symbol (SProxy(..))
import Data.Tuple (Tuple(..), fst, snd)
import Data.Tuple (Tuple(..), fst)
import Data.Tuple.Nested ((/\))
import DOM.Simple.Console (log, log3)
import DOM.Simple.Console (log3)
import DOM.Simple.Event as DE
import Effect (Effect)
import Effect.Aff (Aff, launchAff)
......@@ -28,11 +28,10 @@ import Reactix.DOM.HTML as H
------------------------------------------------------------------------
import Gargantext.Components.Table as T
import Gargantext.Components.Loader (loader)
import Gargantext.Components.Table as T
import Gargantext.Ends (Frontends, url)
import Gargantext.Utils.Reactix as R2
import Gargantext.Routes as Routes
import Gargantext.Routes (AppRoute, SessionRoute(NodeAPI))
import Gargantext.Routes (SessionRoute(NodeAPI))
import Gargantext.Sessions (Session, sessionId, post, delete, put)
import Gargantext.Types (NodeType(..), OrderBy(..), TabType, TabPostQuery(..), AffTableResult)
------------------------------------------------------------------------
......
......@@ -11,7 +11,7 @@ import Gargantext.Components.Forest.Tree.Node.Action (Action(..), ID, Name)
import Gargantext.Components.Forest.Tree.Node (SettingsBox(..), settingsBox)
import Gargantext.Types (NodeType(..), readNodeType)
import Gargantext.Utils.Reactix as R2
import Prelude (Unit, bind, const, discard, map, pure, show, ($), (<>), (>))
import Prelude (Unit, bind, const, discard, map, pure, show, ($), (<>), (>), (<<<))
import Reactix as R
import Reactix.DOM.HTML as H
......@@ -54,34 +54,29 @@ createNodeView d p@{nodeType} (_ /\ setPopupOpen) nodeTypes = R.createElement el
]
where
SettingsBox {edit} = settingsBox nt
maybeEdit = [ if edit
then
maybeEdit = [ if edit then
H.div {className: "form-group"}
[ H.input { type: "text"
, placeholder: "Node name"
, defaultValue: "Write Name here"
, className: "form-control"
, onInput: mkEffectFn1 $ \e -> setNodeName
$ const
$ e .. "target" .. "value"
}
]
[ H.input { type: "text"
, placeholder: "Node name"
, defaultValue: "Write Name here"
, className: "form-control"
, onInput: mkEffectFn1 $ setNodeName <<< const <<< R2.unsafeEventValue
}
]
else
H.div {} []
]
maybeChoose = [ if length nodeTypes > 1
then
R.fragment [H.div {className: "form-group"} $ [ R2.select { className: "form-control"
, onChange: mkEffectFn1 $ \e -> setNodeType
$ const
$ readIt
$ e .. "target" .. "value"
}
(map (\opt -> H.option {} [ H.text $ show opt ]) nodeTypes)
maybeChoose = [ if length nodeTypes > 1 then
R.fragment [
H.div {className: "form-group"} $ [
R2.select { className: "form-control"
, onChange: mkEffectFn1 $ setNodeType <<< const <<< readIt <<< R2.unsafeEventValue
}
(map (\opt -> H.option {} [ H.text $ show opt ]) nodeTypes)
]
-- , showConfig nt
]
]
else
H.button { className : "btn btn-primary"
, type : "button"
......
......@@ -3,13 +3,14 @@ module Gargantext.Components.Forest.Tree.Node.Action.Rename where
import Data.Tuple.Nested ((/\))
import Effect.Aff (Aff, launchAff)
import Effect.Uncurried (mkEffectFn1)
import FFI.Simple ((..))
import Gargantext.Components.Forest.Tree.Node.Action
import Gargantext.Types (NodeType)
import Prelude (Unit, bind, const, discard, pure, ($))
import Prelude (Unit, bind, const, discard, pure, ($), (<<<))
import Reactix as R
import Reactix.DOM.HTML as H
import Gargantext.Components.Forest.Tree.Node.Action
import Gargantext.Types (NodeType)
import Gargantext.Utils.Reactix as R2
-- | START Rename Box
type RenameBoxProps =
......@@ -35,7 +36,7 @@ renameBox d p (true /\ setRenameBoxOpen) = R.createElement el p []
, placeholder: "Rename Node"
, defaultValue: name
, className: "form-control"
, onInput: mkEffectFn1 $ \e -> setRenameNodeName $ const $ e .. "target" .. "value"
, onInput: mkEffectFn1 $ setRenameNodeName <<< const <<< R2.unsafeEventValue
}
]
renameBtn (newName /\ _) =
......
......@@ -64,7 +64,7 @@ uploadFileViewCpt d = R.hooksComponent "UploadFileView" cpt
setMContents $ const $ Just $ UploadFileContents contents
onChangeFileType (fileType /\ setFileType) = mkEffectFn1 $ \e -> do
setFileType $ const $ unsafePartial $ fromJust $ readFileType $ e .. "target" .. "value"
setFileType $ const $ unsafePartial $ fromJust $ readFileType $ R2.unsafeEventValue e
uploadButton :: Int -> R.State (Maybe UploadFileContents) -> R.State FileType -> R.Element
uploadButton id (mContents /\ setMContents) (fileType /\ setFileType) =
......@@ -131,7 +131,7 @@ fileTypeView d p (Just (DroppedFile {contents, fileType}) /\ setDroppedFile) (_
]
where
onChange = mkEffectFn1 $ \e ->
setDroppedFile $ const $ Just $ DroppedFile $ {contents, fileType: readFileType $ e .. "target" .. "value"}
setDroppedFile $ const $ Just $ DroppedFile $ {contents, fileType: readFileType $ R2.unsafeEventValue e}
renderOption opt = H.option {} [ H.text $ show opt ]
panelFooter =
H.div {className: "panel-footer"}
......
......@@ -4,16 +4,16 @@ module Gargantext.Components.GraphExplorer.Search
) where
import Prelude
import Data.Maybe (Maybe(..), fromMaybe)
import Data.Sequence as Seq
import Data.Set as Set
import Data.String as S
import Data.Tuple.Nested ((/\))
import DOM.Simple.Console (log2)
import Effect (Effect)
import FFI.Simple ((..))
import Reactix as R
import Reactix.DOM.HTML as H
import Gargantext.Components.InputWithAutocomplete (inputWithAutocomplete)
import Gargantext.Hooks.Sigmax.Types as SigmaxTypes
type Props = (
......@@ -28,7 +28,8 @@ nodeMatchesSearch s n = S.contains (S.Pattern $ normalize s) (normalize n.label)
normalize = S.toLower
searchNodes :: String -> Seq.Seq (Record SigmaxTypes.Node) -> Seq.Seq (Record SigmaxTypes.Node)
searchNodes s = Seq.filter (nodeMatchesSearch s)
searchNodes "" _ = Seq.empty
searchNodes s nodes = Seq.filter (nodeMatchesSearch s) nodes
nodeSearchControl :: Record Props -> R.Element
nodeSearchControl props = R.createElement sizeButtonCpt props []
......@@ -37,31 +38,35 @@ sizeButtonCpt :: R.Component Props
sizeButtonCpt = R.hooksComponent "NodeSearchControl" cpt
where
cpt {graph, selectedNodeIds} _ = do
search@(search' /\ setSearch) <- R.useState' Nothing
search@(search' /\ setSearch) <- R.useState' ""
pure $
H.div { className: "form-group" }
[ H.div { className: "input-group" }
[ H.input { type: "text"
, className: "form-control"
, defaultValue: fromMaybe "" search'
, on: { input: \e -> setSearch $ const $ Just $ e .. "target" .. "value" }
}
[ inputWithAutocomplete { autocompleteSearch: autocompleteSearch graph
, onAutocompleteClick: \s -> triggerSearch graph s selectedNodeIds
, onEnterPress: \s -> triggerSearch graph s selectedNodeIds
, state: search }
, H.div { className: "btn input-group-addon"
, on: { click: \_ -> triggerSearch graph search selectedNodeIds }
, on: { click: \_ -> triggerSearch graph search' selectedNodeIds }
}
[ H.span { className: "fa fa-search" } [] ]
]
]
autocompleteSearch :: SigmaxTypes.SGraph -> String -> Array String
autocompleteSearch graph s = Seq.toUnfoldable $ (_.label) <$> searchNodes s nodes
where
nodes = SigmaxTypes.graphNodes graph
triggerSearch :: SigmaxTypes.SGraph
-> R.State (Maybe String)
-> String
-> R.State SigmaxTypes.SelectedNodeIds
-> Effect Unit
triggerSearch graph (search /\ setSearch) (_ /\ setSelectedNodeIds) = do
case search of
Nothing -> pure unit
Just s -> do
let nodes = SigmaxTypes.graphNodes graph
triggerSearch graph search (_ /\ setSelectedNodeIds) = do
let nodes = SigmaxTypes.graphNodes graph
let matching = (_.id) <$> searchNodes search nodes
log2 "[triggerSearch] search" search
setSelectedNodeIds $ const $ Set.fromFoldable $ ((_.id) <$> searchNodes s nodes)
setSelectedNodeIds $ const $ Set.fromFoldable matching
module Gargantext.Components.Search.SearchField
( Search, Props, defaultSearch, searchField, searchFieldComponent, isIsTex) where
import Prelude (const, map, pure, show, discard, ($), (&&), (<), (<$>), (<>), (==))
import Prelude (const, map, pure, show, discard, ($), (&&), (<), (<$>), (<>), (==), (<<<))
import Data.Maybe (Maybe(..), maybe)
import Data.String (length)
import Data.Set as Set
......@@ -9,7 +9,6 @@ import Data.Tuple (fst)
import Data.Tuple.Nested ((/\))
import DOM.Simple.Console (log2)
import Gargantext.Utils.Reactix as R2
import FFI.Simple ((..))
import Reactix as R
import Reactix.DOM.HTML as H
import Gargantext.Components.Search.Types -- (Database(..), readDatabase, Lang(..), readLang, Org(..), readOrg, allOrgs, allIMTorgs, HAL_Filters(..), IMT_org(..))
......@@ -185,7 +184,7 @@ langList (lang /\ setLang) langs =
liItem :: Lang -> R.Element
liItem l = H.option {className : "text-primary center"} [ H.text (show l) ]
lang' e = readLang $ e .. "target" .. "value"
lang' = readLang <<< R2.unsafeEventValue
langNav :: R.State Search -> Array Lang -> R.Element
......@@ -260,7 +259,7 @@ databaseInput ({datafield} /\ setSearch) dbs =
liItem db' = H.option {className : "text-primary center"} [ H.text (show db') ]
onChange e = do
let value = e .. "target" .. "value"
let value = R2.unsafeEventValue e
setSearch $ _ {datafield = Just $ External $ readDatabase value }
......@@ -276,7 +275,7 @@ orgInput ({datafield} /\ setSearch) orgs =
liItem :: Org -> R.Element
liItem org = H.option {className : "text-primary center"} [ H.text (show org) ]
onChange e = do
let value = e .. "target" .. "value"
let value = R2.unsafeEventValue e
setSearch $ _ { datafield = Just $ External $ Just $ HAL $ readOrg value }
filterInput :: R.State String -> R.Element
......@@ -284,10 +283,7 @@ filterInput (term /\ setTerm) =
H.div {className: "form-group"} [ H.input { defaultValue: term
, className: "form-control"
, type: "text"
, on: { change: \e -> setTerm
$ const
$ e .. "target" .. "value"
}
, on: { change: setTerm <<< const <<< R2.unsafeEventValue }
, "required pattern": "[[0-9]+[ ]+]*"
-- TODO ^FIXME not sure about the regex comprehension: that should match "123 2334 44545" only (Integers separated by one space)
-- form validation with CSS
......@@ -308,8 +304,7 @@ searchInput ({term} /\ setSearch) =
]
where
onChange e = do
let value = e .. "target" .. "value"
setSearch $ _ {term = value }
setSearch $ _ { term = R2.unsafeEventValue e }
submitButton :: R.State Search
......
......@@ -223,3 +223,6 @@ inputFileBlob e = unsafePartial $ do
dataTransferFileBlob e = unsafePartial $ do
let ff = fromJust $ item 0 $ ((e .. "dataTransfer" .. "files") :: FileList)
pure $ toBlob ff
blur :: DOM.Element -> Effect Unit
blur el = el ... "blur" $ []
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment