Commit aba97048 authored by Przemyslaw Kaminski's avatar Przemyslaw Kaminski

[sessions] store cache state in local storage

parent 9c4f2849
...@@ -36,6 +36,7 @@ import Gargantext.Sessions as Sessions ...@@ -36,6 +36,7 @@ import Gargantext.Sessions as Sessions
import Gargantext.Types as GT import Gargantext.Types as GT
import Gargantext.Utils.Reactix as R2 import Gargantext.Utils.Reactix as R2
thisModule :: String
thisModule = "Gargantext.Components.App" thisModule = "Gargantext.Components.App"
-- TODO (what does this mean?) -- TODO (what does this mean?)
...@@ -71,67 +72,66 @@ appCpt = R.hooksComponentWithModule thisModule "app" cpt where ...@@ -71,67 +72,66 @@ appCpt = R.hooksComponentWithModule thisModule "app" cpt where
, showLogin: snd showLogin , showLogin: snd showLogin
, backend , backend
} }
let defaultView _ = forested $ homeLayout { backend
, lang: LL_EN
, publicBackend
, sessions
, visible: showLogin
}
let mCurrentRoute = fst route let mCurrentRoute = fst route
let withSession sid f = maybe' ( const $ forested let withSession sid f = maybe' defaultView (ff f) (Sessions.lookup sid (fst sessions))
$ homeLayout { lang: LL_EN
, backend let sessionUpdate s = snd sessions $ Sessions.Update s
, publicBackend
, sessions
, visible:showLogin
}
)
(ff f)
(Sessions.lookup sid (fst sessions))
pure $ case fst showLogin of pure $ case fst showLogin of
true -> forested $ login { backend, backends, sessions, visible: showLogin } true -> forested $ login { backend, backends, sessions, visible: showLogin }
false -> false ->
case fst route of case fst route of
Home -> forested $ homeLayout {lang:LL_EN, backend, publicBackend, sessions, visible:showLogin}
Login -> login { backends, sessions, visible: showLogin, backend}
Folder sid nodeId -> withSession sid $ \session -> forested $ corpusLayout { nodeId, session }
FolderPrivate sid nodeId -> withSession sid $ \session -> forested $ corpusLayout { nodeId, session }
FolderPublic sid nodeId -> withSession sid $ \session -> forested $ corpusLayout { nodeId, session }
FolderShared sid nodeId -> withSession sid $ \session -> forested $ corpusLayout { nodeId, session }
Team sid nodeId -> withSession sid $ \session -> forested $ corpusLayout { nodeId, session }
RouteFrameWrite sid nodeId -> withSession sid $ \session -> forested $ frameLayout { nodeId, session }
RouteFrameCalc sid nodeId -> withSession sid $ \session -> forested $ frameLayout { nodeId, session }
RouteFile sid nodeId -> withSession sid $ \session -> forested $ fileLayout { nodeId, session }
Corpus sid nodeId -> withSession sid $ \session -> forested $ corpusLayout { nodeId, session }
Texts sid nodeId -> withSession sid $ \session -> forested $ textsLayout { nodeId, session, frontends }
Lists sid nodeId -> withSession sid $ \session -> forested $ listsLayout { nodeId, session }
Dashboard sid nodeId -> withSession sid $ \session -> forested $ dashboardLayout { nodeId, session }
Annuaire sid nodeId -> withSession sid $ \session -> forested $ annuaireLayout { frontends, nodeId, session } Annuaire sid nodeId -> withSession sid $ \session -> forested $ annuaireLayout { frontends, nodeId, session }
UserPage sid nodeId -> withSession sid $ \session -> forested $ userLayout { frontends, nodeId, session }
ContactPage sid aId nodeId -> withSession sid $ \session -> forested $ annuaireUserLayout { annuaireId: aId, frontends, nodeId, session } ContactPage sid aId nodeId -> withSession sid $ \session -> forested $ annuaireUserLayout { annuaireId: aId, frontends, nodeId, session }
Corpus sid nodeId -> withSession sid $ \session -> forested $ corpusLayout { nodeId, session }
CorpusDocument sid corpusId listId nodeId -> withSession sid $ \session -> forested $ documentLayout { nodeId, listId, session, corpusId: Just corpusId } CorpusDocument sid corpusId listId nodeId -> withSession sid $ \session -> forested $ documentLayout { nodeId, listId, session, corpusId: Just corpusId }
Dashboard sid nodeId -> withSession sid $ \session -> forested $ dashboardLayout { nodeId, session }
Document sid listId nodeId -> Document sid listId nodeId ->
withSession sid $ withSession sid $
\session -> forested $ documentLayout { nodeId, listId, session, corpusId: Nothing } \session -> forested $ documentLayout { nodeId, listId, session, corpusId: Nothing }
Folder sid nodeId -> withSession sid $ \session -> forested $ corpusLayout { nodeId, session }
FolderPrivate sid nodeId -> withSession sid $ \session -> forested $ corpusLayout { nodeId, session }
FolderPublic sid nodeId -> withSession sid $ \session -> forested $ corpusLayout { nodeId, session }
FolderShared sid nodeId -> withSession sid $ \session -> forested $ corpusLayout { nodeId, session }
Home -> forested $ homeLayout { backend, lang:LL_EN, publicBackend, sessions, visible: showLogin }
Lists sid nodeId -> withSession sid $ \session -> forested $ listsLayout { nodeId, session, sessionUpdate }
Login -> login { backend, backends, sessions, visible: showLogin }
PGraphExplorer sid graphId -> PGraphExplorer sid graphId ->
withSession sid $ withSession sid $
\session -> \session ->
simpleLayout handed $ simpleLayout handed $
explorerLayout { frontends explorerLayout { backend
, frontends
, graphId , graphId
, handed: fst handed , handed: fst handed
, mCurrentRoute , mCurrentRoute
, session , session
, sessions: (fst sessions) , sessions: (fst sessions)
, showLogin , showLogin
, backend
--, treeReload --, treeReload
} }
RouteFile sid nodeId -> withSession sid $ \session -> forested $ fileLayout { nodeId, session }
RouteFrameCalc sid nodeId -> withSession sid $ \session -> forested $ frameLayout { nodeId, session }
RouteFrameWrite sid nodeId -> withSession sid $ \session -> forested $ frameLayout { nodeId, session }
Team sid nodeId -> withSession sid $ \session -> forested $ corpusLayout { nodeId, session }
Texts sid nodeId -> withSession sid $ \session -> forested $ textsLayout { frontends, nodeId, session, sessionUpdate }
UserPage sid nodeId -> withSession sid $ \session -> forested $ userLayout { frontends, nodeId, session }
type ForestLayoutProps = type ForestLayoutProps =
( child :: R.Element ( backend :: R.State (Maybe Backend)
, child :: R.Element
, frontends :: Frontends , frontends :: Frontends
, handed :: R.State GT.Handed , handed :: R.State GT.Handed
, reload :: R.State Int , reload :: R.State Int
, route :: AppRoute , route :: AppRoute
, sessions :: Sessions , sessions :: Sessions
, showLogin :: R.Setter Boolean , showLogin :: R.Setter Boolean
, backend :: R.State (Maybe Backend)
) )
forestLayout :: Record ForestLayoutProps -> R.Element forestLayout :: Record ForestLayoutProps -> R.Element
......
...@@ -6,6 +6,9 @@ import Data.Maybe (Maybe(..)) ...@@ -6,6 +6,9 @@ import Data.Maybe (Maybe(..))
import Data.Set as Set import Data.Set as Set
import Data.Tuple (fst, snd) import Data.Tuple (fst, snd)
import Data.Tuple.Nested ((/\)) import Data.Tuple.Nested ((/\))
import Reactix as R
import Reactix.DOM.HTML as H
import Gargantext.AsyncTasks as GAT import Gargantext.AsyncTasks as GAT
import Gargantext.Components.Forest.Tree (treeView) import Gargantext.Components.Forest.Tree (treeView)
import Gargantext.Ends (Frontends, Backend(..)) import Gargantext.Ends (Frontends, Backend(..))
...@@ -14,19 +17,18 @@ import Gargantext.Routes (AppRoute) ...@@ -14,19 +17,18 @@ import Gargantext.Routes (AppRoute)
import Gargantext.Sessions (Session(..), Sessions, OpenNodes, unSessions) import Gargantext.Sessions (Session(..), Sessions, OpenNodes, unSessions)
import Gargantext.Types (Reload, Handed(..)) import Gargantext.Types (Reload, Handed(..))
import Gargantext.Utils.Reactix as R2 import Gargantext.Utils.Reactix as R2
import Reactix as R
import Reactix.DOM.HTML as H
thisModule :: String
thisModule = "Gargantext.Components.Forest" thisModule = "Gargantext.Components.Forest"
type Props = type Props =
( frontends :: Frontends ( backend :: R.State (Maybe Backend)
, frontends :: Frontends
, handed :: Handed , handed :: Handed
, reload :: R.State Int , reload :: R.State Int
, route :: AppRoute , route :: AppRoute
, sessions :: Sessions , sessions :: Sessions
, showLogin :: R.Setter Boolean , showLogin :: R.Setter Boolean
, backend :: R.State (Maybe Backend)
) )
forest :: Record Props -> R.Element forest :: Record Props -> R.Element
...@@ -55,21 +57,18 @@ forestCpt = R.hooksComponentWithModule thisModule "forest" cpt where ...@@ -55,21 +57,18 @@ forestCpt = R.hooksComponentWithModule thisModule "forest" cpt where
where where
trees = tree <$> unSessions sessions trees = tree <$> unSessions sessions
tree s@(Session {treeId}) = tree s@(Session {treeId}) =
treeView { root: treeId treeView { asyncTasks
, asyncTasks
, frontends , frontends
, handed , handed
, mCurrentRoute: Just route , mCurrentRoute: Just route
, openNodes , openNodes
, reload , reload
, root: treeId
, session: s , session: s
} }
plus :: Handed -> R.Setter Boolean -> R.State (Maybe Backend) -> R.Element plus :: Handed -> R.Setter Boolean -> R.State (Maybe Backend) -> R.Element
plus handed showLogin backend = H.div {className: if handed == RightHanded plus handed showLogin backend = H.div { className: handedClass } [
then "flex-start" -- TODO we should use lefthanded SASS class here
else "flex-end"
} [
H.button { title: "Add or remove connections to the server(s)." H.button { title: "Add or remove connections to the server(s)."
, on: {click} , on: {click}
, className: "btn btn-default" , className: "btn btn-default"
...@@ -81,9 +80,14 @@ plus handed showLogin backend = H.div {className: if handed == RightHanded ...@@ -81,9 +80,14 @@ plus handed showLogin backend = H.div {className: if handed == RightHanded
--, 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)
-- [ H.i { className: "material-icons md-36"} [] ] -- [ H.i { className: "material-icons md-36"} [] ]
where where
handedClass = if handed == RightHanded then
"flex-start" -- TODO we should use lefthanded SASS class here
else
"flex-end"
click _ = (snd backend) (const Nothing) click _ = (snd backend) (const Nothing)
*> showLogin (const true) *> showLogin (const true)
...@@ -38,10 +38,10 @@ thisModule = "Gargantext.Components.Login" ...@@ -38,10 +38,10 @@ thisModule = "Gargantext.Components.Login"
-- if not logged user can not save his work -- if not logged user can not save his work
type LoginProps = type LoginProps =
( backends :: Array Backend ( backend :: R.State (Maybe Backend)
, backends :: Array Backend
, sessions :: R2.Reductor Sessions Sessions.Action , sessions :: R2.Reductor Sessions Sessions.Action
, visible :: R.State Boolean , visible :: R.State Boolean
, backend :: R.State (Maybe Backend)
) )
login :: Record LoginProps -> R.Element login :: Record LoginProps -> R.Element
...@@ -104,7 +104,7 @@ chooser props = R.createElement chooserCpt props [] ...@@ -104,7 +104,7 @@ chooser props = R.createElement chooserCpt props []
chooserCpt :: R.Component LoginProps chooserCpt :: R.Component LoginProps
chooserCpt = R.staticComponent "G.C.Login.chooser" cpt where chooserCpt = R.staticComponent "G.C.Login.chooser" cpt where
cpt :: Record LoginProps -> Array R.Element -> R.Element cpt :: Record LoginProps -> Array R.Element -> R.Element
cpt {backend, backends, sessions} _ = cpt { backend, backends, sessions } _ =
R.fragment $ title <> active <> new <> search R.fragment $ title <> active <> new <> search
where where
title = [H.h2 { className: "center modal-title" } [H.text "Instances manager"]] title = [H.h2 { className: "center modal-title" } [H.text "Instances manager"]]
...@@ -152,7 +152,7 @@ renderSessions sessions = R.fragment (renderSession sessions <$> unSessions (fst ...@@ -152,7 +152,7 @@ renderSessions sessions = R.fragment (renderSession sessions <$> unSessions (fst
GHL.clearCache unit GHL.clearCache unit
NTL.clearCache unit NTL.clearCache unit
liftEffect $ log "[renderSessions] cache cleared" liftEffect $ log "[renderSessions] cache cleared"
logOutClick _ = (snd sessions') (Sessions.Logout session) logOutClick _ = snd sessions' $ Sessions.Logout session
renderBackend :: R.State (Maybe Backend) -> Backend -> R.Element renderBackend :: R.State (Maybe Backend) -> Backend -> R.Element
renderBackend state backend@(Backend {name}) = renderBackend state backend@(Backend {name}) =
......
...@@ -27,6 +27,7 @@ import Gargantext.Sessions (Session, get, put, sessionId) ...@@ -27,6 +27,7 @@ import Gargantext.Sessions (Session, get, put, sessionId)
import Gargantext.Types (NodeType(..)) import Gargantext.Types (NodeType(..))
import Gargantext.Utils.Reactix as R2 import Gargantext.Utils.Reactix as R2
thisModule :: String
thisModule = "Gargantext.Components.Nodes.Annuaire.User.Contacts" thisModule = "Gargantext.Components.Nodes.Annuaire.User.Contacts"
display :: String -> Array R.Element -> R.Element display :: String -> Array R.Element -> R.Element
......
module Gargantext.Components.Nodes.Lists where module Gargantext.Components.Nodes.Lists where
import Effect (Effect)
import Effect.Aff (launchAff_) import Effect.Aff (launchAff_)
import Reactix as R import Reactix as R
------------------------------------------------------------------------ ------------------------------------------------------------------------
...@@ -12,9 +13,10 @@ import Gargantext.Components.Nodes.Lists.Types as NT ...@@ -12,9 +13,10 @@ import Gargantext.Components.Nodes.Lists.Types as NT
import Gargantext.Components.Table as Table import Gargantext.Components.Table as Table
import Gargantext.Hooks.Loader (useLoader) import Gargantext.Hooks.Loader (useLoader)
import Gargantext.Prelude import Gargantext.Prelude
import Gargantext.Sessions (Session, sessionId) import Gargantext.Sessions (Session, sessionId, getCacheState, setCacheState)
import Gargantext.Utils.Reactix as R2 import Gargantext.Utils.Reactix as R2
thisModule :: String
thisModule = "Gargantext.Components.Nodes.Lists" thisModule = "Gargantext.Components.Nodes.Lists"
------------------------------------------------------------------------ ------------------------------------------------------------------------
------------------------------------------------------------------------ ------------------------------------------------------------------------
...@@ -22,6 +24,7 @@ thisModule = "Gargantext.Components.Nodes.Lists" ...@@ -22,6 +24,7 @@ thisModule = "Gargantext.Components.Nodes.Lists"
type Props = ( type Props = (
nodeId :: Int nodeId :: Int
, session :: Session , session :: Session
, sessionUpdate :: Session -> Effect Unit
) )
listsLayout :: Record Props -> R.Element listsLayout :: Record Props -> R.Element
...@@ -30,10 +33,10 @@ listsLayout props = R.createElement listsLayoutCpt props [] ...@@ -30,10 +33,10 @@ listsLayout props = R.createElement listsLayoutCpt props []
listsLayoutCpt :: R.Component Props listsLayoutCpt :: R.Component Props
listsLayoutCpt = R.hooksComponentWithModule thisModule "listsLayout" cpt listsLayoutCpt = R.hooksComponentWithModule thisModule "listsLayout" cpt
where where
cpt path@{ nodeId, session } _ = do cpt path@{ nodeId, session, sessionUpdate } _ = do
let sid = sessionId session let sid = sessionId session
pure $ listsLayoutWithKey { key: show sid <> "-" <> show nodeId, nodeId, session } pure $ listsLayoutWithKey { key: show sid <> "-" <> show nodeId, nodeId, session, sessionUpdate }
type KeyProps = ( type KeyProps = (
key :: String key :: String
...@@ -46,10 +49,10 @@ listsLayoutWithKey props = R.createElement listsLayoutWithKeyCpt props [] ...@@ -46,10 +49,10 @@ listsLayoutWithKey props = R.createElement listsLayoutWithKeyCpt props []
listsLayoutWithKeyCpt :: R.Component KeyProps listsLayoutWithKeyCpt :: R.Component KeyProps
listsLayoutWithKeyCpt = R.hooksComponentWithModule thisModule "listsLayoutWithKey" cpt listsLayoutWithKeyCpt = R.hooksComponentWithModule thisModule "listsLayoutWithKey" cpt
where where
cpt { nodeId, session } _ = do cpt { nodeId, session, sessionUpdate } _ = do
let path = { nodeId, session } let path = { nodeId, session }
cacheState <- R.useState' NT.CacheOn cacheState <- R.useState' $ getCacheState NT.CacheOn session nodeId
useLoader path loadCorpusWithChild $ useLoader path loadCorpusWithChild $
\corpusData@{ corpusId, corpusNode: NodePoly poly, defaultListId } -> \corpusData@{ corpusId, corpusNode: NodePoly poly, defaultListId } ->
...@@ -58,7 +61,7 @@ listsLayoutWithKeyCpt = R.hooksComponentWithModule thisModule "listsLayoutWithKe ...@@ -58,7 +61,7 @@ listsLayoutWithKeyCpt = R.hooksComponentWithModule thisModule "listsLayoutWithKe
in in
R.fragment [ R.fragment [
Table.tableHeaderLayout { Table.tableHeaderLayout {
afterCacheStateChange: \_ -> launchAff_ $ clearCache unit afterCacheStateChange
, cacheState , cacheState
, date , date
, desc , desc
...@@ -71,4 +74,8 @@ listsLayoutWithKeyCpt = R.hooksComponentWithModule thisModule "listsLayoutWithKe ...@@ -71,4 +74,8 @@ listsLayoutWithKeyCpt = R.hooksComponentWithModule thisModule "listsLayoutWithKe
, corpusId , corpusId
, session } , session }
] ]
where
afterCacheStateChange cacheState = do
launchAff_ $ clearCache unit
sessionUpdate $ setCacheState session nodeId cacheState
------------------------------------------------------------------------ ------------------------------------------------------------------------
module Gargantext.Components.Nodes.Lists.Types where module Gargantext.Components.Nodes.Lists.Types where
import Data.Argonaut (class DecodeJson, decodeJson, class EncodeJson, encodeJson, (~>), (:=))
import Data.Argonaut.Decode.Error (JsonDecodeError(..))
import Data.Either (Either(..))
import Data.Generic.Rep (class Generic) import Data.Generic.Rep (class Generic)
import Data.Generic.Rep.Eq (genericEq) import Data.Generic.Rep.Eq (genericEq)
import Gargantext.Prelude import Gargantext.Prelude
thisModule :: String
thisModule = "Gargantext.Components.Nodes.Lists.Types" thisModule = "Gargantext.Components.Nodes.Lists.Types"
data CacheState = CacheOn | CacheOff data CacheState = CacheOn | CacheOff
...@@ -12,3 +16,13 @@ data CacheState = CacheOn | CacheOff ...@@ -12,3 +16,13 @@ data CacheState = CacheOn | CacheOff
derive instance genericCacheState :: Generic CacheState _ derive instance genericCacheState :: Generic CacheState _
instance eqCacheState :: Eq CacheState where instance eqCacheState :: Eq CacheState where
eq = genericEq eq = genericEq
instance decodeJsonCacheState :: DecodeJson CacheState where
decodeJson json = do
obj <- decodeJson json
case obj of
"CacheOn" -> pure CacheOn
"CacheOff" -> pure CacheOff
s -> Left $ AtKey s $ TypeMismatch $ "Unknown cache value"
instance encodeJsonCacheState :: EncodeJson CacheState where
encodeJson CacheOn = encodeJson "CacheOn"
encodeJson CacheOff = encodeJson "CacheOff"
...@@ -5,6 +5,7 @@ import Data.Generic.Rep (class Generic) ...@@ -5,6 +5,7 @@ import Data.Generic.Rep (class Generic)
import Data.Generic.Rep.Show (genericShow) import Data.Generic.Rep.Show (genericShow)
import Data.Maybe (Maybe(..)) import Data.Maybe (Maybe(..))
import Data.Tuple.Nested ((/\)) import Data.Tuple.Nested ((/\))
import Effect (Effect)
import Effect.Aff (launchAff_) import Effect.Aff (launchAff_)
import Reactix as R import Reactix as R
import Reactix.DOM.HTML as H import Reactix.DOM.HTML as H
...@@ -20,7 +21,7 @@ import Gargantext.Components.Nodes.Lists.Types as NT ...@@ -20,7 +21,7 @@ import Gargantext.Components.Nodes.Lists.Types as NT
import Gargantext.Components.Tab as Tab import Gargantext.Components.Tab as Tab
import Gargantext.Components.Table as Table import Gargantext.Components.Table as Table
import Gargantext.Ends (Frontends) import Gargantext.Ends (Frontends)
import Gargantext.Sessions (Session, sessionId) import Gargantext.Sessions (Session, Sessions, sessionId, getCacheState, setCacheState)
import Gargantext.Types (CTabNgramType(..), TabSubType(..), TabType(..)) import Gargantext.Types (CTabNgramType(..), TabSubType(..), TabType(..))
import Gargantext.Utils.Reactix as R2 import Gargantext.Utils.Reactix as R2
...@@ -31,6 +32,7 @@ type Props = ( ...@@ -31,6 +32,7 @@ type Props = (
frontends :: Frontends frontends :: Frontends
, nodeId :: Int , nodeId :: Int
, session :: Session , session :: Session
, sessionUpdate :: Session -> Effect Unit
) )
textsLayout :: Record Props -> R.Element textsLayout :: Record Props -> R.Element
...@@ -39,10 +41,14 @@ textsLayout props = R.createElement textsLayoutCpt props [] ...@@ -39,10 +41,14 @@ textsLayout props = R.createElement textsLayoutCpt props []
------------------------------------------------------------------------ ------------------------------------------------------------------------
textsLayoutCpt :: R.Component Props textsLayoutCpt :: R.Component Props
textsLayoutCpt = R.hooksComponentWithModule thisModule "textsLayout" cpt where textsLayoutCpt = R.hooksComponentWithModule thisModule "textsLayout" cpt where
cpt { frontends, nodeId, session } _ = do cpt { frontends, nodeId, session, sessionUpdate } _ = do
let sid = sessionId session let sid = sessionId session
pure $ textsLayoutWithKey { frontends, key: show sid <> "-" <> show nodeId, nodeId, session } pure $ textsLayoutWithKey { frontends
, key: show sid <> "-" <> show nodeId
, nodeId
, session
, sessionUpdate }
type KeyProps = ( type KeyProps = (
key :: String key :: String
...@@ -55,10 +61,10 @@ textsLayoutWithKey props = R.createElement textsLayoutWithKeyCpt props [] ...@@ -55,10 +61,10 @@ textsLayoutWithKey props = R.createElement textsLayoutWithKeyCpt props []
textsLayoutWithKeyCpt :: R.Component KeyProps textsLayoutWithKeyCpt :: R.Component KeyProps
textsLayoutWithKeyCpt = R.hooksComponentWithModule thisModule "textsLayoutWithKey" cpt textsLayoutWithKeyCpt = R.hooksComponentWithModule thisModule "textsLayoutWithKey" cpt
where where
cpt { frontends, nodeId, session } _ = do cpt { frontends, nodeId, session, sessionUpdate } _ = do
cacheState <- R.useState' NT.CacheOn cacheState <- R.useState' $ getCacheState NT.CacheOn session nodeId
pure $ loader {session, nodeId} loadCorpusWithChild $ pure $ loader { nodeId, session } loadCorpusWithChild $
\corpusData@{ corpusId, corpusNode, defaultListId } -> do \corpusData@{ corpusId, corpusNode, defaultListId } -> do
let NodePoly { name, date, hyperdata: Hyperdata h } = corpusNode let NodePoly { name, date, hyperdata: Hyperdata h } = corpusNode
CorpusInfo { authors, desc, query } = getCorpusInfo h.fields CorpusInfo { authors, desc, query } = getCorpusInfo h.fields
...@@ -66,7 +72,7 @@ textsLayoutWithKeyCpt = R.hooksComponentWithModule thisModule "textsLayoutWithKe ...@@ -66,7 +72,7 @@ textsLayoutWithKeyCpt = R.hooksComponentWithModule thisModule "textsLayoutWithKe
title = "Corpus " <> name title = "Corpus " <> name
R.fragment [ R.fragment [
Table.tableHeaderLayout { afterCacheStateChange: \_ -> launchAff_ $ clearCache unit Table.tableHeaderLayout { afterCacheStateChange
, cacheState , cacheState
, date , date
, desc , desc
...@@ -75,6 +81,10 @@ textsLayoutWithKeyCpt = R.hooksComponentWithModule thisModule "textsLayoutWithKe ...@@ -75,6 +81,10 @@ textsLayoutWithKeyCpt = R.hooksComponentWithModule thisModule "textsLayoutWithKe
, user: authors } , user: authors }
, tabs' , tabs'
] ]
where
afterCacheStateChange cacheState = do
launchAff_ $ clearCache unit
sessionUpdate $ setCacheState session nodeId cacheState
data Mode = MoreLikeFav | MoreLikeTrash data Mode = MoreLikeFav | MoreLikeTrash
...@@ -89,7 +99,10 @@ modeTabType :: Mode -> CTabNgramType ...@@ -89,7 +99,10 @@ modeTabType :: Mode -> CTabNgramType
modeTabType MoreLikeFav = CTabAuthors -- TODO modeTabType MoreLikeFav = CTabAuthors -- TODO
modeTabType MoreLikeTrash = CTabSources -- TODO modeTabType MoreLikeTrash = CTabSources -- TODO
type TabsProps = ( frontends :: Frontends, session :: Session, corpusId :: Int, corpusData :: CorpusData ) type TabsProps = ( corpusData :: CorpusData
, corpusId :: Int
, frontends :: Frontends
, session :: Session )
tabs :: Record TabsProps -> R.Element tabs :: Record TabsProps -> R.Element
tabs props = R.createElement tabsCpt props [] tabs props = R.createElement tabsCpt props []
...@@ -113,10 +126,10 @@ tabsCpt = R.hooksComponentWithModule thisModule "tabs" cpt ...@@ -113,10 +126,10 @@ tabsCpt = R.hooksComponentWithModule thisModule "tabs" cpt
trash = docView' TabTrash trash = docView' TabTrash
type DocViewProps a = type DocViewProps a =
( frontends :: Frontends ( corpusData :: CorpusData
, session :: Session
, corpusId :: Int , corpusId :: Int
, corpusData :: CorpusData , frontends :: Frontends
, session :: Session
, tabType :: TabSubType a ) , tabType :: TabSubType a )
docView :: forall a. Record (DocViewProps a) -> R.Element docView :: forall a. Record (DocViewProps a) -> R.Element
......
...@@ -90,7 +90,7 @@ stateParams {pageSize, page, orderBy, searchType} = {offset, limit, orderBy, sea ...@@ -90,7 +90,7 @@ stateParams {pageSize, page, orderBy, searchType} = {offset, limit, orderBy, sea
offset = limit * (page - 1) offset = limit * (page - 1)
type TableHeaderLayoutProps = type TableHeaderLayoutProps =
( afterCacheStateChange :: Unit -> Effect Unit ( afterCacheStateChange :: NT.CacheState -> Effect Unit
, cacheState :: R.State NT.CacheState , cacheState :: R.State NT.CacheState
, date :: String , date :: String
, desc :: String , desc :: String
...@@ -153,9 +153,11 @@ tableHeaderLayoutCpt = R.hooksComponentWithModule thisModule "tableHeaderLayout" ...@@ -153,9 +153,11 @@ tableHeaderLayoutCpt = R.hooksComponentWithModule thisModule "tableHeaderLayout"
cacheText (NT.CacheOn /\ _) = "Cache On" cacheText (NT.CacheOn /\ _) = "Cache On"
cacheText (NT.CacheOff /\ _) = "Cache Off" cacheText (NT.CacheOff /\ _) = "Cache Off"
cacheClick (_ /\ setCacheState) after _ = do cacheClick (cacheState /\ setCacheState) after _ = do
setCacheState cacheStateToggle setCacheState $ const newCacheState
after unit after newCacheState
where
newCacheState = cacheStateToggle cacheState
cacheStateToggle NT.CacheOn = NT.CacheOff cacheStateToggle NT.CacheOn = NT.CacheOff
cacheStateToggle NT.CacheOff = NT.CacheOn cacheStateToggle NT.CacheOff = NT.CacheOn
......
-- | A module for authenticating to create sessions and handling them -- | A module for authenticating to create sessions and handling them
module Gargantext.Sessions where module Gargantext.Sessions where
import DOM.Simple.Console (log2)
import Data.Argonaut (class DecodeJson, decodeJson, class EncodeJson, encodeJson, (:=), (~>), (.:)) import Data.Argonaut (class DecodeJson, decodeJson, class EncodeJson, encodeJson, (:=), (~>), (.:))
import Data.Argonaut.Core (Json, fromArray, jsonEmptyObject, stringify) import Data.Argonaut.Core (Json, fromArray, jsonEmptyObject, stringify)
import Data.Argonaut.Decode.Error (JsonDecodeError(..)) import Data.Argonaut.Decode.Error (JsonDecodeError(..))
...@@ -10,32 +9,38 @@ import Data.Array as A ...@@ -10,32 +9,38 @@ import Data.Array as A
import Data.Either (Either(..)) import Data.Either (Either(..))
import Data.Generic.Rep (class Generic) import Data.Generic.Rep (class Generic)
import Data.Generic.Rep.Eq (genericEq) import Data.Generic.Rep.Eq (genericEq)
import Data.Maybe (Maybe(..)) import Data.Map (Map)
import Data.Map as Map
import Data.Maybe (Maybe(..), fromMaybe)
import Data.Sequence (Seq) import Data.Sequence (Seq)
import Data.Sequence as Seq import Data.Sequence as Seq
import Data.Set (Set) import Data.Set (Set)
import Data.Traversable (traverse) import Data.Traversable (traverse)
import DOM.Simple.Console (log2)
import Effect (Effect) import Effect (Effect)
import Effect.Aff (Aff) import Effect.Aff (Aff)
import Prelude (class Eq, class Show, Unit, const, otherwise, pure, show, unit, ($), (*>), (<*), (<$>), (<>), (==), (/=), (>>=), (<<<), bind)
import Reactix as R
import Web.Storage.Storage (getItem, removeItem, setItem)
import Gargantext.Components.Login.Types (AuthData(..), AuthInvalid(..), AuthRequest(..), AuthResponse(..), TreeId) import Gargantext.Components.Login.Types (AuthData(..), AuthInvalid(..), AuthRequest(..), AuthResponse(..), TreeId)
import Gargantext.Components.Nodes.Lists.Types as NT
import Gargantext.Config.REST as REST import Gargantext.Config.REST as REST
import Gargantext.Ends (class ToUrl, Backend(..), backendUrl, sessionPath, toUrl) import Gargantext.Ends (class ToUrl, Backend(..), backendUrl, sessionPath, toUrl)
import Gargantext.Routes (SessionRoute) import Gargantext.Routes (SessionRoute)
import Gargantext.Types (NodePath, SessionId(..), nodePath) import Gargantext.Types (NodePath, SessionId(..), nodePath)
import Gargantext.Utils.Reactix (getls) import Gargantext.Utils.Reactix (getls)
import Gargantext.Utils.Reactix as R2 import Gargantext.Utils.Reactix as R2
import Prelude (class Eq, class Show, Unit, const, otherwise, pure, show, unit, ($), (*>), (<*), (<$>), (<>), (==), (/=), (>>=), (<<<), bind)
import Reactix as R
import Web.Storage.Storage (getItem, removeItem, setItem)
-- | A Session represents an authenticated session for a user at a -- | A Session represents an authenticated session for a user at a
-- | backend. It contains a token and root tree id. -- | backend. It contains a token and root tree id.
newtype Session = Session newtype Session = Session
{ backend :: Backend { backend :: Backend
, username :: String , caches :: Map Int NT.CacheState -- whether cache is turned on for node id
, token :: String , token :: String
, treeId :: TreeId , treeId :: TreeId
, username :: String
} }
------------------------------------------------------------------------ ------------------------------------------------------------------------
...@@ -64,21 +69,23 @@ sessionId = SessionId <<< show ...@@ -64,21 +69,23 @@ sessionId = SessionId <<< show
-------------------- --------------------
-- | JSON instances -- | JSON instances
instance encodeJsonSession :: EncodeJson Session where instance encodeJsonSession :: EncodeJson Session where
encodeJson (Session {backend, username, token, treeId}) encodeJson (Session { backend, caches, username, token, treeId })
= "backend" := encodeJson backend = "backend" := encodeJson backend
~> "username" := username ~> "caches" := encodeJson caches
~> "token" := token ~> "token" := token
~> "treeId" := treeId ~> "treeId" := treeId
~> "username" := username
~> jsonEmptyObject ~> jsonEmptyObject
instance decodeJsonSession :: DecodeJson Session where instance decodeJsonSession :: DecodeJson Session where
decodeJson json = do decodeJson json = do
obj <- decodeJson json obj <- decodeJson json
backend <- obj .: "backend" backend <- obj .: "backend"
username <- obj .: "username" caches <- obj .: "caches"
token <- obj .: "token" token <- obj .: "token"
treeId <- obj .: "treeId" treeId <- obj .: "treeId"
pure $ Session { backend, username, token, treeId} username <- obj .: "username"
pure $ Session { backend, caches, token, treeId, username }
------------------------------------------------------------------------ ------------------------------------------------------------------------
...@@ -124,10 +131,18 @@ cons :: Session -> Sessions -> Sessions ...@@ -124,10 +131,18 @@ cons :: Session -> Sessions -> Sessions
cons s (Sessions {sessions:ss}) = Sessions {sessions:(Seq.cons s ss)} cons s (Sessions {sessions:ss}) = Sessions {sessions:(Seq.cons s ss)}
tryCons :: Session -> Sessions -> Either Unit Sessions tryCons :: Session -> Sessions -> Either Unit Sessions
tryCons s ss = try (lookup sid ss) where tryCons s ss = try $ lookup sid ss
sid = sessionId s where
try Nothing = Right (cons s ss) sid = sessionId s
try _ = Left unit try Nothing = Right (cons s ss)
try _ = Left unit
update :: Session -> Sessions -> Sessions
update s ss = up $ lookup sid ss
where
sid = sessionId s
up Nothing = cons s ss
up _ = cons s $ remove sid ss
remove :: SessionId -> Sessions -> Sessions remove :: SessionId -> Sessions -> Sessions
remove sid (Sessions {sessions:ss}) = Sessions {sessions: Seq.filter f ss} where remove sid (Sessions {sessions:ss}) = Sessions {sessions: Seq.filter f ss} where
...@@ -157,6 +172,7 @@ instance toUrlSessionString :: ToUrl Session String where ...@@ -157,6 +172,7 @@ instance toUrlSessionString :: ToUrl Session String where
data Action data Action
= Login Session = Login Session
| Logout Session | Logout Session
| Update Session
act :: Sessions -> Action -> Effect Sessions act :: Sessions -> Action -> Effect Sessions
act ss (Login s) = act ss (Login s) =
...@@ -167,18 +183,26 @@ act old@(Sessions ss) (Logout s) = ...@@ -167,18 +183,26 @@ act old@(Sessions ss) (Logout s) =
case tryRemove (sessionId s) old of case tryRemove (sessionId s) old of
Right new -> pure $ new Right new -> pure $ new
_ -> pure old <* log2 "Logged out of stale session:" (sessionId s) _ -> pure old <* log2 "Logged out of stale session:" (sessionId s)
act ss (Update s) = saveSessions $ update s ss
-- Key we will store the data under -- Key we will store the data under
localStorageKey :: String localStorageKey :: String
localStorageKey = "garg-sessions" localStorageKey = "garg-sessions"
empty :: Sessions empty :: Sessions
empty = Sessions {sessions:Seq.empty} empty = Sessions { sessions: Seq.empty }
-- True if there are no sessions stored -- True if there are no sessions stored
null :: Sessions -> Boolean null :: Sessions -> Boolean
null (Sessions {sessions:seq}) = Seq.null seq null (Sessions { sessions: seq }) = Seq.null seq
getCacheState :: NT.CacheState -> Session -> Int -> NT.CacheState
getCacheState defaultCacheState (Session { caches }) nodeId =
fromMaybe defaultCacheState $ Map.lookup nodeId caches
setCacheState :: Session -> Int -> NT.CacheState -> Session
setCacheState (Session session@{ caches }) nodeId cacheState =
Session $ session { caches = Map.insert nodeId cacheState caches }
-- | Will attempt to load saved sessions from localstorage. should log -- | Will attempt to load saved sessions from localstorage. should log
-- | if decoding fails -- | if decoding fails
...@@ -208,6 +232,12 @@ saveSessions sessions = effect *> pure sessions where ...@@ -208,6 +232,12 @@ saveSessions sessions = effect *> pure sessions where
| null sessions = rem | null sessions = rem
| otherwise = set (stringify $ encodeJson sessions) | otherwise = set (stringify $ encodeJson sessions)
updateSession :: Session -> Effect Unit
updateSession s = do
ss <- loadSessions
_ <- saveSessions $ update s ss
pure unit
postAuthRequest :: Backend -> AuthRequest -> Aff (Either String Session) postAuthRequest :: Backend -> AuthRequest -> Aff (Either String Session)
postAuthRequest backend ar@(AuthRequest {username}) = postAuthRequest backend ar@(AuthRequest {username}) =
decode <$> REST.post Nothing (toUrl backend "auth") ar decode <$> REST.post Nothing (toUrl backend "auth") ar
...@@ -215,7 +245,7 @@ postAuthRequest backend ar@(AuthRequest {username}) = ...@@ -215,7 +245,7 @@ postAuthRequest backend ar@(AuthRequest {username}) =
decode (AuthResponse ar2) decode (AuthResponse ar2)
| {inval: Just (AuthInvalid {message})} <- ar2 = Left message | {inval: Just (AuthInvalid {message})} <- ar2 = Left message
| {valid: Just (AuthData {token, tree_id})} <- ar2 = | {valid: Just (AuthData {token, tree_id})} <- ar2 =
Right $ Session { backend, username, token, treeId: tree_id } Right $ Session { backend, caches: Map.empty, token, treeId: tree_id, username }
| otherwise = Left "Invalid response from server" | otherwise = Left "Invalid response from server"
get :: forall a p. DecodeJson a => ToUrl Session p => Session -> p -> Aff a get :: forall a p. DecodeJson a => ToUrl Session p => Session -> p -> Aff a
......
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