Commit 62ea7d7d authored by Karen Konou's avatar Karen Konou

Tree search modal

parent 5cde58d3
...@@ -55,6 +55,7 @@ type Store = ...@@ -55,6 +55,7 @@ type Store =
, showCorpus :: T.Box Boolean , showCorpus :: T.Box Boolean
, showLogin :: T.Box Boolean , showLogin :: T.Box Boolean
, showTree :: T.Box Boolean , showTree :: T.Box Boolean
, showSearch :: T.Box Boolean
, sidePanelLists :: T.Box (Maybe (Record ListsT.SidePanel)) , sidePanelLists :: T.Box (Maybe (Record ListsT.SidePanel))
, sidePanelTexts :: T.Box (Maybe (Record TextsT.SidePanel)) , sidePanelTexts :: T.Box (Maybe (Record TextsT.SidePanel))
, sidePanelState :: T.Box SidePanelState , sidePanelState :: T.Box SidePanelState
...@@ -82,6 +83,7 @@ type State = ...@@ -82,6 +83,7 @@ type State =
, showCorpus :: Boolean , showCorpus :: Boolean
, showLogin :: Boolean , showLogin :: Boolean
, showTree :: Boolean , showTree :: Boolean
, showSearch :: Boolean
, sidePanelLists :: Maybe (Record ListsT.SidePanel) , sidePanelLists :: Maybe (Record ListsT.SidePanel)
, sidePanelTexts :: Maybe (Record TextsT.SidePanel) , sidePanelTexts :: Maybe (Record TextsT.SidePanel)
, sidePanelState :: SidePanelState , sidePanelState :: SidePanelState
...@@ -110,6 +112,7 @@ options = ...@@ -110,6 +112,7 @@ options =
, showCorpus : false , showCorpus : false
, showLogin : false , showLogin : false
, showTree : true , showTree : true
, showSearch : false
, sidePanelLists : ListsT.initialSidePanel , sidePanelLists : ListsT.initialSidePanel
, sidePanelTexts : TextsT.initialSidePanel , sidePanelTexts : TextsT.initialSidePanel
, sidePanelState : InitialClosed , sidePanelState : InitialClosed
......
...@@ -84,7 +84,7 @@ plus :: R2.Leaf Plus ...@@ -84,7 +84,7 @@ plus :: R2.Leaf Plus
plus = R2.leaf plusCpt plus = R2.leaf plusCpt
plusCpt :: R.Component Plus plusCpt :: R.Component Plus
plusCpt = here.component "plus" cpt where plusCpt = here.component "plus" cpt where
cpt { boxes: { backend, showLogin, pinnedTreeId} } _ = do cpt { boxes: { backend, showLogin, showSearch, pinnedTreeId} } _ = do
-- Hooks -- Hooks
{ goToRoute } <- useLinkHandler { goToRoute } <- useLinkHandler
...@@ -98,6 +98,7 @@ plusCpt = here.component "plus" cpt where ...@@ -98,6 +98,7 @@ plusCpt = here.component "plus" cpt where
-- Render -- Render
pure $ pure $
R.fragment [
H.div H.div
{ className: "forest-layout__action" } { className: "forest-layout__action" }
[ [
...@@ -154,6 +155,32 @@ plusCpt = here.component "plus" cpt where ...@@ -154,6 +155,32 @@ plusCpt = here.component "plus" cpt where
] ]
} }
] ]
,
H.div
{ className: "forest-layout__action" }
[
B.tooltipContainer
{ delayShow: 600
, position: TooltipPosition Right
, tooltipSlot:
B.span_ "Search in tree"
, defaultSlot:
B.button
{ className: "forest-layout__action__button"
, callback: \_ -> T.write_ true showSearch
, variant: ButtonVariant Light
}
[
B.icon
{ name: "search"}
,
B.wad_ [ "d-inline-block", "w-1" ]
,
H.text $ "Search"
]
}
]
]
--, H.div { "type": "", className: "fa fa-plus-circle fa-lg"} [] --, H.div { "type": "", className: "fa fa-plus-circle fa-lg"} []
--, H.div { "type": "", className: "fa fa-minus-circle fa-lg"} [] --, H.div { "type": "", className: "fa fa-minus-circle fa-lg"} []
-- TODO same as the one in the Login Modal (same CSS) -- TODO same as the one in the Login Modal (same CSS)
......
...@@ -24,14 +24,15 @@ import Gargantext.Components.Nodes.Corpus.Code (corpusCodeLayout) ...@@ -24,14 +24,15 @@ import Gargantext.Components.Nodes.Corpus.Code (corpusCodeLayout)
import Gargantext.Components.Nodes.Corpus.Dashboard (dashboardLayout) import Gargantext.Components.Nodes.Corpus.Dashboard (dashboardLayout)
import Gargantext.Components.Nodes.Corpus.Document as Document import Gargantext.Components.Nodes.Corpus.Document as Document
import Gargantext.Components.Nodes.Corpus.Phylo as Phylo import Gargantext.Components.Nodes.Corpus.Phylo as Phylo
import Gargantext.Components.Nodes.Graph as Graph
import Gargantext.Components.Nodes.File (fileLayout) import Gargantext.Components.Nodes.File (fileLayout)
import Gargantext.Components.Nodes.Frame as Frame import Gargantext.Components.Nodes.Frame as Frame
import Gargantext.Components.Nodes.Graph as Graph
import Gargantext.Components.Nodes.Home (homeLayout) import Gargantext.Components.Nodes.Home (homeLayout)
import Gargantext.Components.Nodes.Lists as Lists import Gargantext.Components.Nodes.Lists as Lists
import Gargantext.Components.Nodes.Texts as Texts import Gargantext.Components.Nodes.Texts as Texts
import Gargantext.Components.Tile (tileBlock) import Gargantext.Components.Tile (tileBlock)
import Gargantext.Components.TopBar as TopBar import Gargantext.Components.TopBar as TopBar
import Gargantext.Components.TreeSearch (treeSearch)
import Gargantext.Config (defaultFrontends, defaultBackends) import Gargantext.Config (defaultFrontends, defaultBackends)
import Gargantext.Context.Session as SessionContext import Gargantext.Context.Session as SessionContext
import Gargantext.Ends (Backend) import Gargantext.Ends (Backend)
...@@ -100,6 +101,8 @@ routerCpt = here.component "router" cpt where ...@@ -100,6 +101,8 @@ routerCpt = here.component "router" cpt where
{ className: "router" } { className: "router" }
[ [
login' boxes login' boxes
,
treeSearch' boxes
, ,
TopBar.component TopBar.component
{} {}
...@@ -318,6 +321,7 @@ renderRouteCpt = R.memo' $ here.component "renderRoute" cpt where ...@@ -318,6 +321,7 @@ renderRouteCpt = R.memo' $ here.component "renderRoute" cpt where
GR.Home -> home { boxes } [] GR.Home -> home { boxes } []
GR.Lists s n -> lists (sessionNodeProps s n) [] GR.Lists s n -> lists (sessionNodeProps s n) []
GR.Login -> login' boxes GR.Login -> login' boxes
GR.TreeFlat _ _ -> treeSearch' boxes
GR.PGraphExplorer s g -> graphExplorer (sessionNodeProps s g) [] GR.PGraphExplorer s g -> graphExplorer (sessionNodeProps s g) []
GR.PhyloExplorer s g -> phyloExplorer (sessionNodeProps s g) [] GR.PhyloExplorer s g -> phyloExplorer (sessionNodeProps s g) []
GR.RouteFile s n -> routeFile (sessionNodeProps s n) [] GR.RouteFile s n -> routeFile (sessionNodeProps s n) []
...@@ -599,6 +603,12 @@ login' { backend, sessions, showLogin: visible } = ...@@ -599,6 +603,12 @@ login' { backend, sessions, showLogin: visible } =
-------------------------------------------------------------- --------------------------------------------------------------
treeSearch' :: Boxes -> R.Element
treeSearch' { sessions, showSearch: visible } =
treeSearch { sessions, visible }
--------------------------------------------------------------
routeFile :: R2.Component SessionNodeProps routeFile :: R2.Component SessionNodeProps
routeFile = R.createElement routeFileCpt routeFile = R.createElement routeFileCpt
routeFileCpt :: R.Component SessionNodeProps routeFileCpt :: R.Component SessionNodeProps
......
module Gargantext.Components.TreeSearch where
import Gargantext.Prelude
import DOM.Simple as DOM
import Data.Array (filter, head)
import Data.Maybe (Maybe(..), fromMaybe)
import Data.Nullable (Nullable, null)
import Data.String (Pattern(..), contains, toLower)
import Effect (Effect)
import Gargantext.Components.Bootstrap (formSelect')
import Gargantext.Components.Bootstrap as B
import Gargantext.Components.Bootstrap.Types (ModalSizing(..))
import Gargantext.Config.REST (AffRESTError, logRESTError)
import Gargantext.Hooks.LinkHandler (useLinkHandler)
import Gargantext.Hooks.Loader (useLoader)
import Gargantext.Routes (AppRoute(..), appPath, nodeTypeAppRoute)
import Gargantext.Sessions (Session(..), Sessions, get, sessionId, unSessions)
import Gargantext.Sessions.Types (Session)
import Gargantext.Types (NodeID, NodeType, getIcon)
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.TreeSearch"
type Props = (
visible :: T.Box Boolean
, sessions :: T.Box Sessions
)
type StateProps = (
visible :: T.Box Boolean
, sessions :: Sessions
)
type WrapperProps = (
visible :: T.Box Boolean
, sessions :: Sessions
, session :: T.Box (Maybe Session)
)
type ContainerProps = ( visible :: T.Box Boolean, session :: Session )
type RenderContainerProps = ( visible :: T.Box Boolean, session :: Session, searchData :: Array SearchData )
type RenderProps = ( visible :: T.Box Boolean
, session :: Session
, filteredData :: T.Box (Array SearchData)
, searchData :: Array SearchData
, inputRef :: R.Ref (Nullable DOM.Element)
, goToRoute :: AppRoute -> Effect Unit )
type SearchData = { name :: String
, type :: NodeType
, id :: NodeID
}
treeSearch :: R2.Leaf Props
treeSearch = R2.leaf treeSearchCpt
treeSearchCpt :: R.Component Props
treeSearchCpt = here.component "treeSearch" cpt where
cpt { sessions, visible } _ = do
sessions' <- T.useLive T.unequal sessions
pure $
B.baseModal
{ isVisibleBox: visible
, title: Just "Tree Search"
, size: ExtraLargeModalSize
, modalClassName: ""
}
[ treeSearchState {visible, sessions: sessions'} ]
treeSearchState :: R2.Leaf StateProps
treeSearchState = R2.leaf treeSearchStateCpt
treeSearchStateCpt :: R.Component StateProps
treeSearchStateCpt = here.component "treeSearchState" cpt where
cpt { sessions, visible } _ = do
session <- T.useBox $ head $ unSessions sessions
pure $ treeSearchWrapper { visible, session, sessions}
treeSearchWrapper :: R2.Leaf WrapperProps
treeSearchWrapper = R2.leaf treeSearchWrapperCpt
treeSearchWrapperCpt :: R.Component WrapperProps
treeSearchWrapperCpt = here.component "treeSearchWrapper" cpt where
cpt { visible, sessions, session } _ = do
session' <- T.useLive T.unequal session
case session' of
Just s ->
pure $ R.fragment [
formSelect'
{ callback: \v -> T.write_ (Just v) session
, list: unSessions sessions
, value: s
} []
,
treeSearchContainer {visible, session: s}
]
Nothing -> pure $ H.div {} []
treeSearchContainer :: R2.Leaf ContainerProps
treeSearchContainer = R2.leaf treeSearchContainerCpt
treeSearchContainerCpt :: R.Component ContainerProps
treeSearchContainerCpt = here.component "treeSearchContainerCpt" cpt where
cpt {visible, session } _ = do
useLoader { errorHandler
, path: { session }
, loader: loadSearch
, render: \searchData -> treeSearchRenderContainer { visible, session, searchData }
}
where
errorHandler = logRESTError here "[treeSearchContainer]"
treeSearchRenderContainer :: R2.Leaf RenderContainerProps
treeSearchRenderContainer = R2.leaf treeSearchRenderContainerCpt
treeSearchRenderContainerCpt :: R.Component RenderContainerProps
treeSearchRenderContainerCpt = here.component "treeSearchRenderContainer" cpt where
cpt { visible, session, searchData } _ = do
{ goToRoute } <- useLinkHandler
filteredData <- T.useBox searchData
inputRef <- R.useRef null
pure $ treeSearchRender { visible, session, filteredData, searchData, inputRef, goToRoute }
treeSearchRender :: R2.Leaf RenderProps
treeSearchRender = R2.leaf treeSearchRenderCpt
treeSearchRenderCpt :: R.Component RenderProps
treeSearchRenderCpt = here.component "treeSearchRenderCpt" cpt where
cpt { visible, session, filteredData, searchData, inputRef, goToRoute } _ = do
filteredData' <- T.useLive T.unequal filteredData
pure $ H.div {} [
H.div {} [H.input { className: "form-control"
, name: "search"
, ref: inputRef
, on: {change: change }
, type: "value"
, placeholder: "Search..."
}]
, H.div {} $ results filteredData'
]
where
results s = map searchResult s
where
searchResult sd = H.div {} [H.button { className: "mainleaf"
, on: { click: do
T.write_ false visible
goToRoute $ fromMaybe Home $ nodeTypeAppRoute sd.type (sessionId session) sd.id}}
[B.icon {name: getIcon sd.type true} , H.text sd.name]]
change _ = T.write_ (filter (\val -> contains (Pattern $ toLower $ R2.getInputValue inputRef) (toLower val.name)) searchData) filteredData
type LoadProps = ( session :: Session )
loadSearch :: Record LoadProps -> AffRESTError (Array SearchData)
loadSearch { session: s } = get s $ appPath (TreeFlat (sessionId s) (sessionRoot s))
where sessionRoot (Session {treeId}) = treeId
...@@ -23,6 +23,7 @@ data AppRoute ...@@ -23,6 +23,7 @@ data AppRoute
| Home | Home
| Lists SessionId Int | Lists SessionId Int
| Login | Login
| TreeFlat SessionId Int
| PGraphExplorer SessionId Int | PGraphExplorer SessionId Int
| PhyloExplorer SessionId Int | PhyloExplorer SessionId Int
| RouteFile SessionId Int | RouteFile SessionId Int
...@@ -66,6 +67,7 @@ data SessionRoute ...@@ -66,6 +67,7 @@ data SessionRoute
instance Show AppRoute where instance Show AppRoute where
show Home = "Home" show Home = "Home"
show Login = "Login" show Login = "Login"
show (TreeFlat s i) = "treeflat" <> show i <> " (" <> show s <> ")"
show (ForgotPassword u) = "ForgotPassword" <> show u show (ForgotPassword u) = "ForgotPassword" <> show u
show (Folder s i) = "Folder" <> show i <> " (" <> show s <> ")" show (Folder s i) = "Folder" <> show i <> " (" <> show s <> ")"
show (FolderPrivate s i) = "FolderPrivate" <> show i <> " (" <> show s <> ")" show (FolderPrivate s i) = "FolderPrivate" <> show i <> " (" <> show s <> ")"
...@@ -94,6 +96,7 @@ instance Show AppRoute where ...@@ -94,6 +96,7 @@ instance Show AppRoute where
appPath :: AppRoute -> String appPath :: AppRoute -> String
appPath Home = "" appPath Home = ""
appPath Login = "login" appPath Login = "login"
appPath (TreeFlat _ i) = "treeflat/" <> show i
appPath (ForgotPassword u) = "forgotPassword/" <> show u appPath (ForgotPassword u) = "forgotPassword/" <> show u
appPath (Folder s i) = "folder/" <> show s <> "/" <> show i appPath (Folder s i) = "folder/" <> show s <> "/" <> show i
appPath (FolderPrivate s i) = "folderPrivate/" <> show s <> "/" <> show i appPath (FolderPrivate s i) = "folderPrivate/" <> show s <> "/" <> show i
......
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