module Gargantext.Components.Forest where import Data.Array as A import Data.Tuple (fst) import Data.Maybe (Maybe(..), fromMaybe) import Data.Set as Set import Data.Tuple (fst, snd) import Data.Tuple.Nested ((/\)) import DOM.Simple.Console (log, log2) import Reactix as R import Reactix.DOM.HTML as H import Gargantext.AsyncTasks as GAT import Gargantext.Components.Forest.Tree (treeView) import Gargantext.Components.TopBar (topBar) import Gargantext.Ends (Frontends, Backend(..)) import Gargantext.Prelude import Gargantext.Routes (AppRoute) import Gargantext.Sessions (Session(..), Sessions, OpenNodes, unSessions) import Gargantext.Types (Handed(..)) import Gargantext.Utils.Reactix as R2 import Gargantext.Utils.Reload as GUR thisModule :: String thisModule = "Gargantext.Components.Forest" type Props = ( appReload :: GUR.ReloadS , asyncTasksRef :: R.Ref (Maybe GAT.Reductor) , backend :: R.State (Maybe Backend) , currentRoute :: AppRoute , frontends :: Frontends , handed :: Handed , sessions :: Sessions , showLogin :: R.Setter Boolean , treeReloadRef :: GUR.ReloadWithInitializeRef ) forest :: R2.Component Props forest = R.createElement forestCpt forestCpt :: R.Component Props forestCpt = R.hooksComponentWithModule thisModule "forest" cpt where cpt { appReload , asyncTasksRef , backend , currentRoute , frontends , handed , sessions , showLogin , treeReloadRef } _ = do -- NOTE: this is a hack to reload the tree view on demand reload <- GUR.new asyncTasks <- GAT.useTasks appReload reload openNodes <- R2.useLocalStorageState R2.openNodesKey (Set.empty :: OpenNodes) -- TODO If `treeReloadRef` is set, `reload` state should be updated R.useEffect' $ do R.setRef asyncTasksRef $ Just asyncTasks GUR.initializeI treeReloadRef reload R2.useCache ( frontends /\ currentRoute /\ sessions /\ fst openNodes /\ fst appReload /\ fst reload /\ (fst asyncTasks).storage /\ handed ) (cpt' openNodes asyncTasks appReload reload showLogin backend) cpt' openNodes asyncTasks appReload reload showLogin backend (frontends /\ currentRoute /\ sessions /\ _ /\ _ /\ _ /\ _ /\ handed) = do pure $ H.div { className: "forest" } $ [plus handed showLogin backend] <> trees where trees = tree <$> unSessions sessions tree s@(Session {treeId}) = treeView { appReload , asyncTasks , currentRoute , frontends , handed , openNodes , reload , root: treeId , session: s } [] plus :: Handed -> R.Setter Boolean -> R.State (Maybe Backend) -> R.Element plus handed showLogin backend = H.div { className: "row" } [ H.button { className: "btn btn-secondary col-5 " <> if handed == RightHanded then "ml-1 mr-auto" else "ml-auto mr-1" , on: {click} , title: "Add or remove connections to the server(s)." } [ H.div { "type": "" , className: "fa fa-universal-access" -- fa-lg } [H.text " Log in/out "] , H.div {} [H.text " "] --, H.div { "type": "", className: "fa fa-plus-circle fa-lg"} [] --, H.div { "type": "", className: "fa fa-minus-circle fa-lg"} [] ] ] -- TODO same as the one in the Login Modal (same CSS) -- [ H.i { className: "material-icons md-36"} [] ] where click _ = (snd backend) (const Nothing) *> showLogin (const true) ------------------------- type ForestLayoutProps = ( appReload :: GUR.ReloadS , asyncTasksRef :: R.Ref (Maybe GAT.Reductor) , backend :: R.State (Maybe Backend) , currentRoute :: AppRoute , frontends :: Frontends , handed :: R.State Handed , sessions :: Sessions , showLogin :: R.Setter Boolean , treeReloadRef :: GUR.ReloadWithInitializeRef ) forestLayout :: R2.Component ForestLayoutProps forestLayout props = R.createElement forestLayoutCpt props forestLayoutCpt :: R.Component ForestLayoutProps forestLayoutCpt = R.hooksComponentWithModule thisModule "forestLayout" cpt where cpt props@{ handed } children = do pure $ R.fragment [ topBar { handed } [], forestLayoutMain props children ] -- a component, for which first child element is placed inside the top bar -- while the remaining ones are put into the main view forestLayoutWithTopBar :: R2.Component ForestLayoutProps forestLayoutWithTopBar props = R.createElement forestLayoutWithTopBarCpt props forestLayoutWithTopBarCpt :: R.Component ForestLayoutProps forestLayoutWithTopBarCpt = R.hooksComponentWithModule thisModule "forestLayoutWithTopBar" cpt where cpt props@{ handed } children = do let { head: topBarChild, tail: mainChildren } = fromMaybe { head: H.div {} [], tail: [] } $ A.uncons children pure $ R.fragment [ topBar { handed } [ topBarChild ] , forestLayoutMain props mainChildren ] forestLayoutMain :: R2.Component ForestLayoutProps forestLayoutMain props = R.createElement forestLayoutMainCpt props forestLayoutMainCpt :: R.Component ForestLayoutProps forestLayoutMainCpt = R.hooksComponentWithModule thisModule "forestLayoutMain" cpt where cpt props children = do pure $ forestLayoutRaw props [ mainPage {} children ] forestLayoutRaw :: R2.Component ForestLayoutProps forestLayoutRaw props = R.createElement forestLayoutRawCpt props forestLayoutRawCpt :: R.Component ForestLayoutProps forestLayoutRawCpt = R.hooksComponentWithModule thisModule "forestLayoutRaw" cpt where cpt { appReload , asyncTasksRef , backend , currentRoute , frontends , handed , sessions , showLogin , treeReloadRef } children = do let ordering = case fst handed of LeftHanded -> A.reverse RightHanded -> identity pure $ R2.row $ ordering ([ H.div { className: "col-md-2", style: { paddingTop: "60px" } } [ forest { appReload , asyncTasksRef , backend , currentRoute , frontends , handed: fst handed , sessions , showLogin , treeReloadRef } [] ] ] <> children) mainPage :: R2.Component () mainPage = R.createElement mainPageCpt mainPageCpt :: R.Component () mainPageCpt = R.hooksComponentWithModule thisModule "mainPage" cpt where cpt {} children = do pure $ H.div {className: "col-md-10"} [ H.div {id: "page-wrapper"} [ H.div {className: "container-fluid"} children ] ]