Commit c82a7f6b authored by Przemyslaw Kaminski's avatar Przemyslaw Kaminski

[errors] implement errors view in various places

parent 85f4f9f2
Pipeline #1710 canceled with stage
-- TODO: this module should be replaced by FacetsTable
module Gargantext.Components.DocsTable where
import Gargantext.Prelude
import Prelude
import Control.Monad.Error.Class (throwError)
import DOM.Simple.Console (log2)
import DOM.Simple.Event as DE
import Data.Argonaut (class EncodeJson, jsonEmptyObject, (:=), (~>))
import Data.Array as A
import Data.Either (Either(..))
import Data.Either (Either)
import Data.Generic.Rep (class Generic)
import Data.Lens ((^.))
import Data.Lens.At (at)
......@@ -24,7 +19,7 @@ import Data.String as Str
import Data.Symbol (SProxy(..))
import Data.Tuple (Tuple(..))
import Effect (Effect)
import Effect.Aff (Aff, error, launchAff_)
import Effect.Aff (Aff)
import Effect.Class (liftEffect)
import Gargantext.Components.Category (rating)
import Gargantext.Components.Category.Types (Star(..))
......@@ -36,11 +31,11 @@ import Gargantext.Components.Table.Types as TT
import Gargantext.Config.REST (RESTError)
import Gargantext.Ends (Frontends, url)
import Gargantext.Hooks.Loader (useLoader, useLoaderWithCacheAPI, HashedResponse(..))
import Gargantext.Prelude (class Ord, Unit, bind, const, discard, identity, mempty, otherwise, pure, show, unit, ($), (/=), (<$>), (<<<), (<>), (==))
import Gargantext.Prelude
import Gargantext.Routes (SessionRoute(NodeAPI))
import Gargantext.Routes as Routes
import Gargantext.Sessions (Session, sessionId, get, delete)
import Gargantext.Types (ListId, NodeID, NodeType(..), OrderBy(..), SidePanelState(..), TableResult, TabSubType, TabType, showTabType')
import Gargantext.Types (FrontendError, ListId, NodeID, NodeType(..), OrderBy(..), SidePanelState(..), TabSubType, TabType, TableResult, showTabType')
import Gargantext.Utils (sortWith)
import Gargantext.Utils.CacheAPI as GUC
import Gargantext.Utils.QueryString (joinQueryStrings, mQueryParam, mQueryParamS, queryParam, queryParamS)
......@@ -66,6 +61,7 @@ type Path a =
type CommonProps =
( cacheState :: T.Box NT.CacheState
, errors :: T.Box (Array FrontendError)
, frontends :: Frontends
, listId :: Int
, mCorpusId :: Maybe Int
......@@ -101,7 +97,6 @@ _localCategories = prop (SProxy :: SProxy "localCategories")
docViewLayout :: Record LayoutProps -> R.Element
docViewLayout props = R.createElement docViewLayoutCpt props []
docViewLayoutCpt :: R.Component LayoutProps
docViewLayoutCpt = here.component "docViewLayout" cpt
where
......@@ -118,11 +113,11 @@ type Props = (
docView :: R2.Component Props
docView = R.createElement docViewCpt
docViewCpt :: R.Component Props
docViewCpt = here.component "docView" cpt where
cpt { layout: { cacheState
, chart
, errors
, frontends
, listId
, mCorpusId
......@@ -147,6 +142,7 @@ docViewCpt = here.component "docView" cpt where
, if showSearch then searchBar { query } [] else H.div {} []
, H.div {className: "col-md-12"}
[ pageLayout { cacheState
, errors
, frontends
, key: "docView-" <> (show cacheState')
, listId
......@@ -167,7 +163,6 @@ type SearchBarProps =
searchBar :: R2.Component SearchBarProps
searchBar = R.createElement searchBarCpt
searchBarCpt :: R.Component SearchBarProps
searchBarCpt = here.component "searchBar" cpt
where
......@@ -268,6 +263,7 @@ pageLayout = R.createElement pageLayoutCpt
pageLayoutCpt :: R.Component PageLayoutProps
pageLayoutCpt = here.component "pageLayout" cpt where
cpt props@{ cacheState
, errors
, frontends
, listId
, mCorpusId
......@@ -303,6 +299,7 @@ pageLayoutCpt = here.component "pageLayout" cpt where
case cacheState' of
NT.CacheOn -> do
let paint (Tuple count docs) = page { documents: docs
, errors
, layout: props { totalRecords = count }
, params } []
mkRequest :: PageParams -> GUC.Request
......@@ -310,6 +307,7 @@ pageLayoutCpt = here.component "pageLayout" cpt where
useLoaderWithCacheAPI {
cacheEndpoint: getPageHash session
, errors
, handleResponse
, mkRequest
, path
......@@ -339,13 +337,13 @@ pageLayoutCpt = here.component "pageLayout" cpt where
type PageProps = (
documents :: Array DocumentsView
, layout :: Record PageLayoutProps
, params :: TT.Params
, errors :: T.Box (Array FrontendError)
, layout :: Record PageLayoutProps
, params :: TT.Params
)
page :: R2.Component PageProps
page = R.createElement pageCpt
pageCpt :: R.Component PageProps
pageCpt = here.component "pageCpt" cpt where
cpt { documents, layout, params } _ = do
......@@ -361,7 +359,6 @@ type PagePaintProps = (
pagePaint :: R2.Component PagePaintProps
pagePaint = R.createElement pagePaintCpt
pagePaintCpt :: R.Component PagePaintProps
pagePaintCpt = here.component "pagePaintCpt" cpt
where
......
module Gargantext.Components.ErrorsView where
import Gargantext.Prelude
import Data.Array (deleteAt)
import Data.FunctorWithIndex (mapWithIndex)
import Data.Maybe (Maybe(..))
import Reactix as R
import Reactix.DOM.HTML as H
import Toestand as T
import Gargantext.Types (FrontendError(..))
import Gargantext.Utils.ReactBootstrap as RB
import Gargantext.Utils.Reactix as R2
here :: R2.Here
here = R2.here "Gargantext.Components.ErrorsView"
type ErrorsProps =
( errors :: T.Box (Array FrontendError) )
errorsView :: R2.Component ErrorsProps
errorsView = R.createElement errorsViewCpt
errorsViewCpt :: R.Component ErrorsProps
errorsViewCpt = here.component "errorsView" cpt
where
cpt { errors } _ = do
errors' <- T.useLive T.unequal errors
pure $ H.div {}
( mapWithIndex (showError errors) errors' )
showError errors i (FStringError { error }) =
RB.alert { dismissible: true
, onClose
, variant: "danger" } [ H.text error ]
where
onClose = do
here.log2 "click!" error
T.modify_ (\es -> case deleteAt i es of
Nothing -> es
Just es' -> es'
) errors
showError errors i (FRESTError { error }) =
RB.alert { dismissible: true
, onClose
, variant: "danger" } [ H.text $ show error ]
where
onClose = do
here.log2 "click!" error
T.modify_ (\es -> case deleteAt i es of
Nothing -> es
Just es' -> es'
) errors
......@@ -6,15 +6,9 @@ import Data.Either (Either(..))
import Data.Maybe (Maybe(..), fromMaybe)
import Data.Nullable (null)
import Data.Traversable (traverse_)
import DOM.Simple.Console (log, log2)
import Effect (Effect)
import Effect.Aff (Aff, error)
import Effect.Class (liftEffect)
import Reactix as R
import Reactix.DOM.HTML as H
import Record as Record
import Toestand as T
import Gargantext.AsyncTasks as GAT
import Gargantext.Components.Forest.Tree.Node.Action (Action(..))
import Gargantext.Components.Forest.Tree.Node.Action.Add (AddNodeValue(..), addNode)
......@@ -31,15 +25,20 @@ import Gargantext.Components.Forest.Tree.Node.Box (nodePopupView)
import Gargantext.Components.Forest.Tree.Node.Tools.FTree (FTree, LNode(..), NTree(..), fTreeID)
import Gargantext.Components.Forest.Tree.Node.Tools.SubTree.Types (SubTreeOut(..))
import Gargantext.Config.REST (RESTError)
import Gargantext.Config.Utils (handleRESTError)
import Gargantext.Hooks.Loader (useLoader)
import Gargantext.Prelude (Ordering, Unit, bind, compare, discard, pure, unit, void, ($), (<$>), (<>))
import Gargantext.Routes (AppRoute(Home), SessionRoute(..), appPath, nodeTypeAppRoute)
import Gargantext.Sessions (Session, get, sessionId)
import Gargantext.Types (NodeType(..))
import Gargantext.Types (FrontendError, NodeType(..))
import Gargantext.Types as GT
import Gargantext.Utils.Popover as Popover
import Gargantext.Utils.Reactix as R2
import Gargantext.Utils.Toestand as T2
import Reactix as R
import Reactix.DOM.HTML as H
import Record as Record
import Toestand as T
foreign import back :: Effect Unit
foreign import link :: String -> Effect Unit
......@@ -48,11 +47,12 @@ here :: R2.Here
here = R2.here "Gargantext.Components.FolderView"
type Props =
( nodeId :: Int
, session :: Session
, backFolder :: Boolean
, tasks :: T.Box GAT.Storage
( backFolder :: Boolean
, errors :: T.Box (Array FrontendError)
, nodeId :: Int
, reloadForest :: T.Box T2.Reload
, session :: Session
, tasks :: T.Box GAT.Storage
)
data FolderStyle = FolderUp | FolderChild
......@@ -61,35 +61,43 @@ folderView :: R2.Leaf Props
folderView props = R.createElement folderViewCpt props []
folderViewCpt :: R.Component Props
folderViewCpt = here.component "folderViewCpt" cpt where
cpt {nodeId, session, backFolder, tasks, reloadForest} _ = do
cpt { errors, nodeId, session, backFolder, tasks, reloadForest } _ = do
setPopoverRef <- R.useRef Nothing
reload <- T.useBox T2.newReload
reload' <- T.useLive T.unequal reload
useLoader { errorHandler
, loader: loadFolders
, path: { nodeId, session, reload: reload'}
, render: \folders -> folderViewMain {folders, nodeId, session, backFolder, tasks, reload, setPopoverRef, reloadForest} }
, render: \folders -> folderViewMain { backFolder
, errors
, folders
, nodeId
, session
, tasks
, reload
, setPopoverRef
, reloadForest} }
where
errorHandler err = here.log2 "[folderView] RESTError" err
type FolderViewProps =
(
nodeId :: Int
, folders:: FTree
, session :: Session
, backFolder :: Boolean
, tasks :: T.Box GAT.Storage
, reload :: T.Box T2.Reload
, reloadForest :: T.Box T2.Reload
( backFolder :: Boolean
, errors :: T.Box (Array FrontendError)
, folders :: FTree
, nodeId :: Int
, reload :: T.Box T2.Reload
, reloadForest :: T.Box T2.Reload
, session :: Session
, setPopoverRef :: R.Ref (Maybe (Boolean -> Effect Unit))
, tasks :: T.Box GAT.Storage
)
folderViewMain :: Record FolderViewProps -> R.Element
folderViewMain props = R.createElement folderViewMainCpt props []
folderViewMainCpt :: R.Component FolderViewProps
folderViewMainCpt = here.component "folderViewMainCpt" cpt where
cpt { backFolder
, errors
, folders: NTree (LNode {parent_id: parentId, nodeType}) (folders)
, nodeId
, reload
......@@ -100,22 +108,23 @@ folderViewMainCpt = here.component "folderViewMainCpt" cpt where
let foldersS = A.sortBy sortFolders folders
let backHome = isBackHome nodeType
let parent = makeParentFolder parentId session backFolder backHome
let children = makeFolderElements foldersS {session, setPopoverRef, nodeId, tasks, reload, reloadForest}
let children = makeFolderElements foldersS { errors, session, setPopoverRef, nodeId, tasks, reload, reloadForest }
pure $ H.div {className: "fv folders"} $ parent <> children
makeFolderElements foldersS props = makeFolderElementsMap <$> foldersS where
makeFolderElementsMap :: NTree LNode -> R.Element
makeFolderElementsMap (NTree (LNode node) _) = folder {style: FolderChild
, text: node.name
makeFolderElementsMap (NTree (LNode node) _) = folder { errors: props.errors
, nodeId: node.id
, nodeType: node.nodeType
, session: props.session
, setPopoverRef: props.setPopoverRef
, parentId: props.nodeId
, tasks: props.tasks
, reload: props.reload
, reloadForest: props.reloadForest} []
, reloadForest: props.reloadForest
, session: props.session
, setPopoverRef: props.setPopoverRef
, style: FolderChild
, text: node.name } []
makeParentFolder :: Maybe Int -> Session -> Boolean -> Boolean -> Array R.Element
makeParentFolder (Just parentId) session _ _ =
......@@ -171,23 +180,22 @@ folderSimpleCpt = here.component "folderSimpleCpt" cpt where
getFolderPath nodeType sid nodeId = appPath $ fromMaybe Home $ nodeTypeAppRoute nodeType sid nodeId
type FolderProps =
(
setPopoverRef :: R.Ref (Maybe (Boolean -> Effect Unit))
, parentId :: Int
, tasks :: T.Box GAT.Storage
, reload :: T.Box T2.Reload
, reloadForest :: T.Box T2.Reload
( errors :: T.Box (Array FrontendError)
, parentId :: Int
, reload :: T.Box T2.Reload
, reloadForest :: T.Box T2.Reload
, setPopoverRef :: R.Ref (Maybe (Boolean -> Effect Unit))
, tasks :: T.Box GAT.Storage
| FolderSimpleProps
)
folder :: R2.Component FolderProps
folder = R.createElement folderCpt
folderCpt :: R.Component FolderProps
folderCpt = here.component "folderCpt" cpt where
cpt props@{style, text, nodeId, session, nodeType, setPopoverRef, parentId, tasks, reload, reloadForest} _ = do
cpt props@{ errors, style, text, nodeId, session, nodeType, setPopoverRef, parentId, tasks, reload, reloadForest } _ = do
let sid = sessionId session
let dispatch a = performAction a {setPopoverRef, session, nodeId, parentId, tasks, reload, reloadForest}
let dispatch a = performAction a { errors, nodeId, parentId, tasks, reload, reloadForest, session, setPopoverRef }
popoverRef <- R.useRef null
R.useEffect' $ do
......@@ -226,11 +234,12 @@ folderCpt = here.component "folderCpt" cpt where
<> "Click here to execute one of them." } []
]
mNodePopupView props opc = nodePopupView {onPopoverClose: opc
,nodeType: props.nodeType
, name: props.text
mNodePopupView props opc = nodePopupView { dispatch: props.dispatch
, errors: props.errors
, id: props.nodeId
, dispatch: props.dispatch
, onPopoverClose: opc
, nodeType: props.nodeType
, name: props.text
, session: props.session
, handed: GT.RightHanded
}
......@@ -264,14 +273,14 @@ loadFolders :: Record LoadProps -> Aff (Either RESTError FTree)
loadFolders {nodeId, session} = get session $ TreeFirstLevel (Just nodeId) ""
type PerformActionProps =
(
setPopoverRef :: R.Ref (Maybe (Boolean -> Effect Unit))
, session :: Session
, nodeId :: Int
, parentId :: Int
, tasks :: T.Box GAT.Storage
, reload :: T.Box T2.Reload
, reloadForest :: T.Box T2.Reload
( errors :: T.Box (Array FrontendError)
, nodeId :: Int
, parentId :: Int
, reload :: T.Box T2.Reload
, reloadForest :: T.Box T2.Reload
, setPopoverRef :: R.Ref (Maybe (Boolean -> Effect Unit))
, session :: Session
, tasks :: T.Box GAT.Storage
)
performAction :: Action -> Record PerformActionProps -> Aff Unit
......@@ -286,13 +295,13 @@ performAction = performAction' where
performAction' (AddNode name nodeType) p = addNode' name nodeType p
performAction' (UploadFile nodeType fileType mName contents) p = uploadFile' nodeType fileType mName contents p
performAction' (UploadArbitraryFile mName blob) p = uploadArbitraryFile' mName blob p
performAction' DownloadNode _ = liftEffect $ log "[performAction] DownloadNode"
performAction' DownloadNode _ = liftEffect $ here.log "[performAction] DownloadNode"
performAction' (MoveNode {params}) p = moveNode params p
performAction' (MergeNode {params}) p = mergeNode params p
performAction' (LinkNode { nodeType, params }) p = linkNode nodeType params p
performAction' NoAction _ = liftEffect $ log "[performAction] NoAction"
performAction' NoAction _ = liftEffect $ here.log "[performAction] NoAction"
performAction' ClosePopover p = closePopover p
performAction' _ _ = liftEffect $ log "[performAction] unsupported action"
performAction' _ _ = liftEffect $ here.log "[performAction] unsupported action"
closePopover { setPopoverRef } =
liftEffect $ traverse_ (\set -> set false) (R.readRef setPopoverRef)
......@@ -311,59 +320,63 @@ performAction = performAction' where
doSearch task { tasks, nodeId: id } = liftEffect $ do
GAT.insert id task tasks
log2 "[performAction] DoSearch task:" task
here.log2 "[performAction] DoSearch task:" task
updateNode params p@{ tasks, nodeId: id } = do
task <- updateRequest params p.session id
liftEffect $ do
updateNode params p@{ errors, tasks, nodeId: id } = do
eTask <- updateRequest params p.session id
handleRESTError errors eTask $ \task -> liftEffect $ do
GAT.insert id task tasks
log2 "[performAction] UpdateNode task:" task
here.log2 "[performAction] UpdateNode task:" task
shareTeam username p@{ nodeId: id} =
void $ Share.shareReq p.session id $ Share.ShareTeamParams {username}
shareTeam username p@{ errors, nodeId: id} = do
eTask <- Share.shareReq p.session id $ Share.ShareTeamParams {username}
handleRESTError errors eTask $ \_task -> pure unit
sharePublic params p = traverse_ f params where
sharePublic params p@{ errors } = traverse_ f params where
f (SubTreeOut { in: inId, out }) = do
void $ Share.shareReq p.session inId $ Share.SharePublicParams { node_id: out }
eTask <- Share.shareReq p.session inId $ Share.SharePublicParams { node_id: out }
handleRESTError errors eTask $ \_task -> pure unit
refreshFolders p
addContact params p@{ nodeId: id } =
void $ Contact.contactReq p.session id params
uploadFile' nodeType fileType mName contents p@{ tasks, nodeId: id } = do
task <- uploadFile p.session nodeType id fileType {mName, contents}
liftEffect $ do
uploadFile' nodeType fileType mName contents p@{ errors, tasks, nodeId: id } = do
eTask <- uploadFile { contents, fileType, id, nodeType, mName, session: p.session }
handleRESTError errors eTask $ \task -> liftEffect $ do
GAT.insert id task tasks
log2 "[performAction] UploadFile, uploaded, task:" task
here.log2 "[performAction] UploadFile, uploaded, task:" task
uploadArbitraryFile' mName blob p@{ tasks, nodeId: id } = do
uploadArbitraryFile' mName blob p@{ errors, tasks, nodeId: id } = do
eTask <- uploadArbitraryFile p.session id { blob, mName }
case eTask of
Left _err -> throwError $ error "[uploadArbitraryFile] RESTError"
Right task -> do
liftEffect $ do
GAT.insert id task tasks
log2 "[performAction] UploadArbitraryFile, uploaded, task:" task
moveNode params p = traverse_ f params where
handleRESTError errors eTask $ \task -> liftEffect $ do
GAT.insert id task tasks
here.log2 "[performAction] UploadArbitraryFile, uploaded, task:" task
moveNode params p@{ errors } = traverse_ f params where
f (SubTreeOut { in: in', out }) = do
void $ moveNodeReq p.session in' out
eTask <- moveNodeReq p.session in' out
handleRESTError errors eTask $ \_task -> pure unit
refreshFolders p
mergeNode params p = traverse_ f params where
mergeNode params p@{ errors } = traverse_ f params where
f (SubTreeOut { in: in', out }) = do
void $ mergeNodeReq p.session in' out
eTask <- mergeNodeReq p.session in' out
handleRESTError errors eTask $ \_task -> pure unit
refreshFolders p
linkNode nodeType params p = traverse_ f params where
linkNode nodeType params p@{ errors } = traverse_ f params where
f (SubTreeOut { in: in', out }) = do
void $ linkNodeReq p.session nodeType in' out
eTask <- linkNodeReq p.session nodeType in' out
handleRESTError errors eTask $ \_task -> pure unit
refreshFolders p
renameNode name p@{ nodeId: id } = do
void $ rename p.session id $ RenameValue { text: name }
renameNode name p@{ errors, nodeId: id } = do
eTask <- rename p.session id $ RenameValue { text: name }
handleRESTError errors eTask $ \_task -> pure unit
refreshFolders p
addNode' name nodeType p@{ nodeId: id } = do
void $ addNode p.session id $ AddNodeValue {name, nodeType}
addNode' name nodeType p@{ errors, nodeId: id } = do
eTask <- addNode p.session id $ AddNodeValue {name, nodeType}
handleRESTError errors eTask $ \_task -> pure unit
refreshFolders p
......@@ -14,7 +14,7 @@ import Gargantext.Components.Forest.Tree (treeLoader)
import Gargantext.Ends (Frontends, Backend)
import Gargantext.Routes (AppRoute)
import Gargantext.Sessions (Session(..), Sessions, OpenNodes, unSessions)
import Gargantext.Types (Handed, switchHanded)
import Gargantext.Types (FrontendError, Handed, switchHanded)
import Gargantext.Utils.Reactix as R2
import Gargantext.Utils.Toestand as T2
import Reactix as R
......@@ -36,6 +36,7 @@ type Common =
type Props =
( backend :: T.Box (Maybe Backend)
, errors :: T.Box (Array FrontendError)
, forestOpen :: T.Box OpenNodes
, reloadForest :: T2.ReloadS
, sessions :: T.Box Sessions
......@@ -53,6 +54,7 @@ forest = R.createElement forestCpt
forestCpt :: R.Component Props
forestCpt = here.component "forest" cpt where
cpt props@{ backend
, errors
, forestOpen
, frontends
, handed
......@@ -81,7 +83,8 @@ forestCpt = here.component "forest" cpt where
common = RX.pick props :: Record Common
trees handed' sessions' = (tree handed') <$> unSessions sessions'
tree handed' s@(Session {treeId}) =
treeLoader { forestOpen
treeLoader { errors
, forestOpen
, frontends
, handed: handed'
, reload: reloadForest
......
......@@ -2,21 +2,13 @@ module Gargantext.Components.Forest.Tree where
import Gargantext.Prelude
import Control.Monad.Error.Class (throwError)
import Data.Array as A
import Data.Either (Either(..))
import Data.Either (Either)
import Data.Maybe (Maybe(..))
import Data.Traversable (traverse_, traverse)
import DOM.Simple.Console (log, log2)
import Effect (Effect)
import Effect.Aff (Aff, error)
import Effect.Aff (Aff)
import Effect.Class (liftEffect)
import Reactix as R
import Reactix.DOM.HTML as H
import Record as Record
import Record.Extra as RecordE
import Toestand as T
import Gargantext.AsyncTasks as GAT
import Gargantext.Components.Forest.Tree.Node (nodeSpan)
import Gargantext.Components.Forest.Tree.Node.Action (Action(..))
......@@ -33,16 +25,22 @@ import Gargantext.Components.Forest.Tree.Node.Action.Upload (uploadFile, uploadA
import Gargantext.Components.Forest.Tree.Node.Tools.FTree (FTree, LNode(..), NTree(..), fTreeID)
import Gargantext.Components.Forest.Tree.Node.Tools.SubTree.Types (SubTreeOut(..))
import Gargantext.Config.REST (RESTError)
import Gargantext.Config.Utils (handleRESTError)
import Gargantext.Ends (Frontends)
import Gargantext.Hooks.Loader (useLoader)
import Gargantext.Routes (AppRoute)
import Gargantext.Routes as GR
import Gargantext.Sessions (OpenNodes, Session, get, mkNodeId)
import Gargantext.Sessions.Types (useOpenNodesMemberBox, openNodesInsert, openNodesDelete)
import Gargantext.Types (Handed, ID, isPublic, publicize, switchHanded)
import Gargantext.Types (FrontendError, Handed, ID, isPublic, publicize, switchHanded)
import Gargantext.Types as GT
import Gargantext.Utils.Reactix as R2
import Gargantext.Utils.Toestand as T2
import Reactix as R
import Reactix.DOM.HTML as H
import Record as Record
import Record.Extra as RecordE
import Toestand as T
here :: R2.Here
here = R2.here "Gargantext.Components.Forest.Tree"
......@@ -61,8 +59,9 @@ type Global =
| Universal )
-- Shared by every component here
type Common = (
forestOpen :: T.Box OpenNodes
type Common =
( errors :: T.Box (Array FrontendError)
, forestOpen :: T.Box OpenNodes
, reload :: T2.ReloadS
| Global
)
......@@ -105,12 +104,12 @@ tree :: R2.Leaf TreeProps
tree props = R.createElement treeCpt props []
treeCpt :: R.Component TreeProps
treeCpt = here.component "tree" cpt where
cpt p@{ reload, session, tree: NTree (LNode { id, name, nodeType }) children } _ = do
cpt p@{ errors, reload, session, tree: NTree (LNode { id, name, nodeType }) children } _ = do
setPopoverRef <- R.useRef Nothing
folderOpen <- useOpenNodesMemberBox nodeId p.forestOpen
pure $ H.ul { className: ulClass }
[ H.li { className: childrenClass children' }
[ nodeSpan (nsprops { folderOpen, name, id, nodeType, setPopoverRef, isLeaf })
[ nodeSpan (nsprops { errors, folderOpen, name, id, nodeType, setPopoverRef, isLeaf })
[ renderChildren (Record.merge p { childProps: { children', folderOpen, render: tree } } ) [] ]
]
]
......@@ -125,7 +124,7 @@ treeCpt = here.component "tree" cpt where
extra' = Record.merge extra { dispatch, reload } where
dispatch a = performAction a (Record.merge common' spr) where
common' = RecordE.pick p :: Record PACommon
spr = { setPopoverRef: extra.setPopoverRef }
spr = { errors, setPopoverRef: extra.setPopoverRef }
pub (LNode n@{ nodeType: t }) = LNode (n { nodeType = publicize t })
childrenClass [] = "no-children"
childrenClass _ = "with-children"
......@@ -167,7 +166,8 @@ renderTreeChildrenCpt = here.component "renderTreeChildren" cpt where
--- The properties tree shares in common with performAction
type PACommon =
( forestOpen :: T.Box OpenNodes
( errors :: T.Box (Array FrontendError)
, forestOpen :: T.Box OpenNodes
, reloadTree :: T2.ReloadS
, session :: Session
, tasks :: T.Box GAT.Storage
......@@ -220,83 +220,88 @@ deleteNode' nt p@{ tree: (NTree (LNode {id, parent_id}) _) } = do
doSearch task p@{ tasks, tree: NTree (LNode {id}) _ } = liftEffect $ do
GAT.insert id task tasks
log2 "[performAction] DoSearch task:" task
updateNode params p@{ tasks, tree: (NTree (LNode {id}) _) } = do
task <- updateRequest params p.session id
liftEffect $ do
here.log2 "[doSearch] DoSearch task:" task
updateNode params p@{ errors, tasks, tree: (NTree (LNode {id}) _) } = do
eTask <- updateRequest params p.session id
handleRESTError errors eTask $ \task -> liftEffect $ do
GAT.insert id task tasks
log2 "[performAction] UpdateNode task:" task
here.log2 "[updateNode] UpdateNode task:" task
renameNode name p@{ tree: (NTree (LNode {id}) _) } = do
void $ rename p.session id $ RenameValue { text: name }
renameNode name p@{ errors, tree: (NTree (LNode {id}) _) } = do
eTask <- rename p.session id $ RenameValue { text: name }
handleRESTError errors eTask $ \_task -> pure unit
refreshTree p
shareTeam username p@{ tree: (NTree (LNode {id}) _)} =
void $ Share.shareReq p.session id $ Share.ShareTeamParams {username}
shareTeam username p@{ errors, tree: (NTree (LNode {id}) _)} = do
eTask <- Share.shareReq p.session id $ Share.ShareTeamParams {username}
handleRESTError errors eTask $ \_task -> pure unit
sharePublic params p@{ forestOpen } = traverse_ f params where
sharePublic params p@{ errors, forestOpen } = traverse_ f params where
f (SubTreeOut { in: inId, out }) = do
void $ Share.shareReq p.session inId $ Share.SharePublicParams { node_id: out }
liftEffect $ T.modify_ (openNodesInsert (mkNodeId p.session out)) forestOpen
eTask <- Share.shareReq p.session inId $ Share.SharePublicParams { node_id: out }
handleRESTError errors eTask $ \_task -> do
liftEffect $ T.modify_ (openNodesInsert (mkNodeId p.session out)) forestOpen
refreshTree p
addContact params p@{ errors, tree: (NTree (LNode {id}) _) } = do
eTask <- Contact.contactReq p.session id params
handleRESTError errors eTask $ \_task -> pure unit
addNode' name nodeType p@{ errors, forestOpen, tree: (NTree (LNode { id }) _) } = do
eId <- addNode p.session id $ AddNodeValue {name, nodeType}
handleRESTError errors eId $ \_id -> liftEffect $ do
liftEffect $ T.modify_ (openNodesInsert (mkNodeId p.session id)) forestOpen
refreshTree p
addContact params p@{ tree: (NTree (LNode {id}) _) } =
void $ Contact.contactReq p.session id params
addNode' name nodeType p@{ forestOpen, tree: (NTree (LNode { id }) _) } = do
task <- addNode p.session id $ AddNodeValue {name, nodeType}
liftEffect $ T.modify_ (openNodesInsert (mkNodeId p.session id)) forestOpen
refreshTree p
uploadFile' nodeType fileType mName contents p@{ tasks, tree: (NTree (LNode { id }) _) } = do
task <- uploadFile p.session nodeType id fileType {mName, contents}
liftEffect $ do
uploadFile' nodeType fileType mName contents p@{ errors, tasks, tree: (NTree (LNode { id }) _) } = do
eTask <- uploadFile { contents, fileType, id, mName, nodeType, session: p.session }
handleRESTError errors eTask $ \task -> liftEffect $ do
GAT.insert id task tasks
log2 "[performAction] UploadFile, uploaded, task:" task
here.log2 "[uploadFile'] UploadFile, uploaded, task:" task
uploadArbitraryFile' mName blob p@{ tasks, tree: (NTree (LNode { id }) _) } = do
uploadArbitraryFile' mName blob p@{ errors, tasks, tree: (NTree (LNode { id }) _) } = do
eTask <- uploadArbitraryFile p.session id { blob, mName }
case eTask of
Left err -> throwError $ error $ "[uploadArbitraryFile'] RESTError"
Right task -> do
liftEffect $ do
GAT.insert id task tasks
log2 "[performAction] UploadArbitraryFile, uploaded, task:" task
moveNode params p@{ forestOpen, session } = traverse_ f params where
handleRESTError errors eTask $ \task -> liftEffect $ do
GAT.insert id task tasks
here.log2 "[uploadArbitraryFile'] UploadArbitraryFile, uploaded, task:" task
moveNode params p@{ errors, forestOpen, session } = traverse_ f params where
f (SubTreeOut { in: in', out }) = do
void $ moveNodeReq p.session in' out
eTask <- moveNodeReq p.session in' out
handleRESTError errors eTask $ \_task -> pure unit
liftEffect $ T.modify_ (openNodesInsert (mkNodeId session out)) forestOpen
refreshTree p
mergeNode params p = traverse_ f params where
mergeNode params p@{ errors } = traverse_ f params where
f (SubTreeOut { in: in', out }) = do
void $ mergeNodeReq p.session in' out
eTask <- mergeNodeReq p.session in' out
handleRESTError errors eTask $ \_task -> pure unit
refreshTree p
linkNode nodeType params p = traverse_ f params where
linkNode nodeType params p@{ errors } = traverse_ f params where
f (SubTreeOut { in: in', out }) = do
void $ linkNodeReq p.session nodeType in' out
eTask <- linkNodeReq p.session nodeType in' out
handleRESTError errors eTask $ \_task -> pure unit
refreshTree p
-- | This thing is basically a hangover from when garg was a thermite
-- | application. we should slowly get rid of it.
performAction :: Action -> Record PerformActionProps -> Aff Unit
performAction (DeleteNode nt) p = deleteNode' nt p
performAction (DoSearch task) p = doSearch task p
performAction (UpdateNode params) p = updateNode params p
performAction (RenameNode name) p = renameNode name p
performAction (ShareTeam username) p = shareTeam username p
performAction (SharePublic { params }) p = sharePublic params p
performAction (AddContact params) p = addContact params p
performAction (AddNode name nodeType) p = addNode' name nodeType p
performAction (DeleteNode nt) p = deleteNode' nt p
performAction (DoSearch task) p = doSearch task p
performAction (UpdateNode params) p = updateNode params p
performAction (RenameNode name) p = renameNode name p
performAction (ShareTeam username) p = shareTeam username p
performAction (SharePublic { params }) p = sharePublic params p
performAction (AddContact params) p = addContact params p
performAction (AddNode name nodeType) p = addNode' name nodeType p
performAction (UploadFile nodeType fileType mName contents) p = uploadFile' nodeType fileType mName contents p
performAction (UploadArbitraryFile mName blob) p = uploadArbitraryFile' mName blob p
performAction DownloadNode _ = liftEffect $ log "[performAction] DownloadNode"
performAction (MoveNode {params}) p = moveNode params p
performAction (MergeNode {params}) p = mergeNode params p
performAction (LinkNode { nodeType, params }) p = linkNode nodeType params p
performAction RefreshTree p = refreshTree p
performAction NoAction _ = liftEffect $ log "[performAction] NoAction"
performAction ClosePopover p = closePopover p
performAction (UploadArbitraryFile mName blob) p = uploadArbitraryFile' mName blob p
performAction DownloadNode _ = liftEffect $ here.log "[performAction] DownloadNode"
performAction (MoveNode {params}) p = moveNode params p
performAction (MergeNode {params}) p = mergeNode params p
performAction (LinkNode { nodeType, params }) p = linkNode nodeType params p
performAction RefreshTree p = refreshTree p
performAction NoAction _ = liftEffect $ here.log "[performAction] NoAction"
performAction ClosePopover p = closePopover p
......@@ -10,12 +10,6 @@ import Data.Tuple.Nested ((/\))
import Effect (Effect)
import Effect.Aff (Aff, launchAff)
import Effect.Class (liftEffect)
import React.SyntheticEvent as E
import Reactix as R
import Reactix.DOM.HTML as H
import Record as Record
import Toestand as T
import Gargantext.AsyncTasks as GAT
import Gargantext.Components.Forest.Tree.Node.Action (Action(..))
import Gargantext.Components.Forest.Tree.Node.Action.Upload (DroppedFile(..), fileTypeView)
......@@ -33,19 +27,25 @@ import Gargantext.Ends (Frontends)
import Gargantext.Hooks.Loader (useLoader)
import Gargantext.Routes as Routes
import Gargantext.Sessions (Session, sessionId)
import Gargantext.Types (Name, ID, reverseHanded)
import Gargantext.Types (FrontendError, ID, Name, reverseHanded)
import Gargantext.Types as GT
import Gargantext.Utils.Popover as Popover
import Gargantext.Utils.Reactix as R2
import Gargantext.Utils.Toestand as T2
import Gargantext.Version as GV
import React.SyntheticEvent as E
import Reactix as R
import Reactix.DOM.HTML as H
import Record as Record
import Toestand as T
here :: R2.Here
here = R2.here "Gargantext.Components.Forest.Tree.Node"
-- Main Node
type NodeMainSpanProps =
( folderOpen :: T.Box Boolean
( errors :: T.Box (Array FrontendError)
, folderOpen :: T.Box Boolean
, frontends :: Frontends
, id :: ID
, isLeaf :: IsLeaf
......@@ -64,7 +64,6 @@ type IsLeaf = Boolean
nodeSpan :: R2.Component NodeMainSpanProps
nodeSpan = R.createElement nodeSpanCpt
nodeSpanCpt :: R.Component NodeMainSpanProps
nodeSpanCpt = here.component "nodeSpan" cpt
where
......@@ -77,11 +76,11 @@ nodeSpanCpt = here.component "nodeSpan" cpt
nodeMainSpan :: R2.Component NodeMainSpanProps
nodeMainSpan = R.createElement nodeMainSpanCpt
nodeMainSpanCpt :: R.Component NodeMainSpanProps
nodeMainSpanCpt = here.component "nodeMainSpan" cpt
where
cpt props@{ dispatch
, errors
, folderOpen
, frontends
, handed
......@@ -129,10 +128,11 @@ nodeMainSpanCpt = here.component "nodeMainSpan" cpt
, fileTypeView { dispatch, droppedFile, id, isDragOver, nodeType }
, H.div {} (map (\t -> asyncProgressBar { asyncTask: t
, barType: Pie
, nodeId: id
, onFinish: onTaskFinish id t
, session } []
, barType: Pie
, errors
, nodeId: id
, onFinish: onTaskFinish id t
, session } []
) currentTasks'
)
, if nodeType == GT.NodeUser
......@@ -188,7 +188,7 @@ nodeMainSpanCpt = here.component "nodeMainSpan" cpt
name' {name: n, nodeType: nt} = if nt == GT.NodeUser then show session else n
mNodePopupView props'@{ id: i, nodeType: nt, handed: h } opc =
nodePopupView { dispatch, handed: h, id: i, name: name' props'
nodePopupView { dispatch, errors, handed: h, id: i, name: name' props'
, nodeType: nt, onPopoverClose: opc, session }
popOverIcon =
......
module Gargantext.Components.Forest.Tree.Node.Action where
import Data.Generic.Rep (class Generic)
import Data.Eq.Generic (genericEq)
import Data.Maybe (Maybe(..))
import Effect.Aff (Aff)
......
......@@ -2,7 +2,6 @@ module Gargantext.Components.Forest.Tree.Node.Action.Add where
import Gargantext.Prelude
import Control.Monad.Error.Class (throwError)
import Data.Array (head, length)
import Data.Either (Either(..))
import Data.Generic.Rep (class Generic)
......@@ -11,16 +10,7 @@ import Data.Newtype (class Newtype)
import Data.String (Pattern(..), indexOf)
import Data.Tuple.Nested ((/\))
import Effect (Effect)
import Effect.Aff (Aff, error, launchAff_)
import Effect.Class (liftEffect)
import Reactix as R
import Reactix.DOM.HTML as H
import Simple.JSON as JSON
import Toestand as T
import Web.HTML (window)
import Web.HTML.Navigator (userAgent)
import Web.HTML.Window (navigator)
import Effect.Aff (Aff, launchAff_)
import Gargantext.Components.Forest.Tree.Node.Action (Action(..))
import Gargantext.Components.Forest.Tree.Node.Settings (SettingsBox(..), settingsBox)
import Gargantext.Components.Forest.Tree.Node.Tools (formChoiceSafe, panel, submitButton)
......@@ -33,6 +23,13 @@ import Gargantext.Types (NodeType(..), charCodeIcon)
import Gargantext.Types as GT
import Gargantext.Utils (nbsp)
import Gargantext.Utils.Reactix as R2
import Reactix as R
import Reactix.DOM.HTML as H
import Simple.JSON as JSON
import Toestand as T
import Web.HTML (window)
import Web.HTML.Navigator (userAgent)
import Web.HTML.Window (navigator)
here :: R2.Here
here = R2.here "Gargantext.Components.Forest.Tree.Node.Action.Add"
......@@ -43,12 +40,12 @@ addNode session parentId = post session $ GR.NodeAPI GT.Node (Just parentId) ""
addNodeAsync :: Session
-> GT.ID
-> AddNodeValue
-> Aff GT.AsyncTaskWithType
-> Aff (Either RESTError GT.AsyncTaskWithType)
addNodeAsync session parentId q = do
eTask :: Either RESTError GT.AsyncTask <- post session p q
case eTask of
Left _err -> liftEffect $ throwError $ error "[addNodeAsync] RESTError"
Right task -> pure $ GT.AsyncTaskWithType { task, typ: GT.AddNode }
Left err -> pure $ Left err
Right task -> pure $ Right $ GT.AsyncTaskWithType { task, typ: GT.AddNode }
where
p = GR.NodeAPI GT.Node (Just parentId) (GT.asyncTaskTypePath GT.AddNode)
......
......@@ -2,19 +2,11 @@ module Gargantext.Components.Forest.Tree.Node.Action.Link where
import Gargantext.Prelude
import Control.Monad.Error.Class (throwError)
import Data.Either (Either(..))
import Data.Either (Either)
import Data.Generic.Rep (class Generic)
import Data.Maybe (Maybe(..))
import Data.Show.Generic (genericShow)
import Effect.Aff (Aff)
import Effect.Class (liftEffect)
import Effect.Exception (error)
import Reactix as R
import Reactix.DOM.HTML as H
import Simple.JSON as JSON
import Toestand as T
import Gargantext.Components.Forest.Tree.Node.Action (Action(..))
import Gargantext.Components.Forest.Tree.Node.Tools (submitButton, panel)
import Gargantext.Components.Forest.Tree.Node.Tools.SubTree (subTreeView, SubTreeParamsIn)
......@@ -23,6 +15,10 @@ import Gargantext.Routes (SessionRoute(..))
import Gargantext.Sessions (Session, post)
import Gargantext.Types as GT
import Gargantext.Utils.Reactix as R2
import Reactix as R
import Reactix.DOM.HTML as H
import Simple.JSON as JSON
import Toestand as T
here :: R2.Here
here = R2.here "Gargantext.Components.Forest.Tree.Node.Action.Link"
......@@ -35,13 +31,11 @@ derive newtype instance JSON.ReadForeign LinkNodeReq
derive newtype instance JSON.WriteForeign LinkNodeReq
linkNodeReq :: Session -> Maybe GT.NodeType -> GT.ID -> GT.ID -> Aff GT.AsyncTaskWithType
linkNodeReq :: Session -> Maybe GT.NodeType -> GT.ID -> GT.ID -> Aff (Either RESTError GT.AsyncTaskWithType)
linkNodeReq session nt fromId toId = do
eTask :: Either RESTError GT.AsyncTask <- post session (NodeAPI GT.Node (Just fromId) "update")
(LinkNodeReq { nodeType: linkNodeType nt, id: toId })
case eTask of
Left _err -> liftEffect $ throwError $ error "[linkNodeReq] RESTError"
Right task -> pure $ GT.AsyncTaskWithType { task, typ: GT.UpdateNode }
pure $ (\task -> GT.AsyncTaskWithType { task, typ: GT.UpdateNode }) <$> eTask
linkNodeType :: Maybe GT.NodeType -> GT.NodeType
linkNodeType (Just GT.Corpus) = GT.Annuaire
......
module Gargantext.Components.Forest.Tree.Node.Action.Search where
import Gargantext.Prelude
import Data.Maybe (Maybe)
import Effect (Effect)
import Effect.Aff (Aff, launchAff)
import Reactix as R
import Reactix.DOM.HTML as H
import Toestand as T
import Gargantext.Prelude
import Gargantext.Components.Forest.Tree.Node.Action (Action(..))
import Gargantext.Components.Forest.Tree.Node.Action.Add (NodePopup)
import Gargantext.Components.Forest.Tree.Node.Action.Search.SearchBar (searchBar)
import Gargantext.Components.Forest.Tree.Node.Action.Search.SearchField (defaultSearch)
import Gargantext.Components.Lang (allLangs)
import Gargantext.Sessions (Session)
import Gargantext.Types (ID)
import Gargantext.Types (FrontendError, ID)
import Gargantext.Types as GT
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.Forest.Tree.Node.Action.Search"
......@@ -25,6 +24,7 @@ here = R2.here "Gargantext.Components.Forest.Tree.Node.Action.Search"
type Props =
( dispatch :: Action -> Aff Unit
, errors :: T.Box (Array FrontendError)
, id :: Maybe ID
, nodePopup :: Maybe NodePopup
, session :: Session )
......@@ -35,12 +35,13 @@ actionSearch = R.createElement actionSearchCpt
actionSearchCpt :: R.Component Props
actionSearchCpt = here.component "actionSearch" cpt
where
cpt { dispatch, id, nodePopup, session } _ = do
cpt { dispatch, errors, id, nodePopup, session } _ = do
search <- T.useBox $ defaultSearch { node_id = id }
pure $ R.fragment [ H.p { className: "action-search" }
[ H.text $ "Search and create a private "
<> "corpus with the search query as corpus name." ]
, searchBar { langs: allLangs
, searchBar { errors
, langs: allLangs
, onSearch: searchOn dispatch nodePopup
, search
, session
......
......@@ -3,24 +3,25 @@ module Gargantext.Components.Forest.Tree.Node.Action.Search.SearchBar
, searchBar
) where
import Data.Tuple.Nested ((/\))
import Effect (Effect)
import Reactix as R
import Reactix.DOM.HTML as H
import Toestand as T
import Gargantext.Components.Forest.Tree.Node.Action.Search.Types
import Effect (Effect)
import Gargantext.Components.Forest.Tree.Node.Action.Search.SearchField (searchField)
import Gargantext.Components.Forest.Tree.Node.Action.Search.Types -- (Database, SearchQuery(..), defaultSearchQuery, performSearch, Lang(..))
import Gargantext.Components.Lang (Lang)
import Gargantext.Prelude (Unit, pure, ($))
import Gargantext.Sessions (Session)
import Gargantext.Types (FrontendError)
import Gargantext.Types as GT
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.Forest.Tree.Node.Action.Search.SearchBar"
type Props = ( langs :: Array Lang
type Props = ( errors :: T.Box (Array FrontendError)
, langs :: Array Lang
, onSearch :: GT.AsyncTaskWithType -> Effect Unit
, search :: T.Box Search
, session :: Session
......@@ -28,14 +29,14 @@ type Props = ( langs :: Array Lang
searchBar :: R2.Component Props
searchBar = R.createElement searchBarCpt
searchBarCpt :: R.Component Props
searchBarCpt = here.component "searchBar" cpt
where
cpt { langs, onSearch, search, session } _ = do
cpt { errors, langs, onSearch, search, session } _ = do
--onSearchChange session s
pure $ H.div { className: "search-bar" }
[ searchField { databases:allDatabases
, errors
, langs
, onSearch
, search
......
module Gargantext.Components.Forest.Tree.Node.Action.Search.SearchField where
import Gargantext.Prelude
import DOM.Simple.Console (log, log2)
import Data.Maybe (Maybe(..), maybe, fromMaybe)
import Data.Nullable (null)
import Data.Newtype (over)
import Data.Nullable (null)
import Data.Set as Set
import Data.Tuple.Nested ((/\))
import Effect (Effect)
import Effect.Aff (launchAff_)
import Effect.Class (liftEffect)
import Reactix as R
import Reactix.DOM.HTML as H
import Toestand as T
import Gargantext.Prelude
import Gargantext.Components.Forest.Tree.Node.Action.Search.Frame (searchIframes)
import Gargantext.Components.Forest.Tree.Node.Action.Search.Types (DataField(..), Database(..), IMT_org(..), Org(..), SearchQuery(..), allIMTorgs, allOrgs, dataFields, defaultSearchQuery, doc, performSearch, datafield2database, Search)
import Gargantext.Components.InputWithEnter (inputWithEnter)
import Gargantext.Components.Lang (Lang)
import Gargantext.Config.Utils (handleRESTError)
import Gargantext.Sessions (Session)
import Gargantext.Components.Forest.Tree.Node.Action.Search.Frame (searchIframes)
import Gargantext.Types (FrontendError)
import Gargantext.Types as GT
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.Forest.Tree.Node.Action.Search.SearchField"
......@@ -38,6 +39,7 @@ defaultSearch = { databases: Empty
type Props =
-- list of databases to search, or parsers to use on uploads
( databases :: Array Database
, errors :: T.Box (Array FrontendError)
, langs :: Array Lang
-- State hook for a search, how we get data in and out
, onSearch :: GT.AsyncTaskWithType -> Effect Unit
......@@ -47,11 +49,10 @@ type Props =
searchField :: R2.Component Props
searchField = R.createElement searchFieldCpt
searchFieldCpt :: R.Component Props
searchFieldCpt = here.component "searchField" cpt
where
cpt props@{ onSearch, search } _ = do
cpt props@{ errors, onSearch, search, session } _ = do
search' <- T.useLive T.unequal search
iframeRef <- R.useRef null
let params =
......@@ -86,7 +87,7 @@ searchFieldCpt = here.component "searchField" cpt
]
]
let button = submitButton {onSearch, search, session: props.session} []
let button = submitButton { errors, onSearch, search, session } []
pure $
......@@ -103,7 +104,6 @@ type ComponentProps =
componentIMT :: R2.Component ComponentProps
componentIMT = R.createElement componentIMTCpt
componentIMTCpt :: R.Component ComponentProps
componentIMTCpt = here.component "componentIMT" cpt
where
......@@ -242,7 +242,6 @@ type LangNavProps =
langNav :: R2.Component LangNavProps
langNav = R.createElement langNavCpt
langNavCpt :: R.Component LangNavProps
langNavCpt = here.component "langNav" cpt
where
......@@ -267,7 +266,6 @@ type DataFieldNavProps =
dataFieldNav :: R2.Component DataFieldNavProps
dataFieldNav = R.createElement dataFieldNavCpt
dataFieldNavCpt :: R.Component DataFieldNavProps
dataFieldNavCpt = here.component "dataFieldNav" cpt
where
......@@ -306,7 +304,6 @@ type DatabaseInputProps = (
databaseInput :: R2.Component DatabaseInputProps
databaseInput = R.createElement databaseInputCpt
databaseInputCpt :: R.Component DatabaseInputProps
databaseInputCpt = here.component "databaseInput" cpt
where
......@@ -347,7 +344,6 @@ type OrgInputProps =
orgInput :: R2.Component OrgInputProps
orgInput = R.createElement orgInputCpt
orgInputCpt :: R.Component OrgInputProps
orgInputCpt = here.component "orgInput" cpt
where
......@@ -390,7 +386,6 @@ type SearchInputProps =
searchInput :: R2.Component SearchInputProps
searchInput = R.createElement searchInputCpt
searchInputCpt :: R.Component SearchInputProps
searchInputCpt = here.component "searchInput" cpt
where
......@@ -429,39 +424,40 @@ searchInputCpt = here.component "searchInput" cpt
-- setSearch $ _ { term = value }
type SubmitButtonProps =
( onSearch :: GT.AsyncTaskWithType -> Effect Unit
( errors :: T.Box (Array FrontendError)
, onSearch :: GT.AsyncTaskWithType -> Effect Unit
, search :: T.Box Search
, session :: Session
)
submitButton :: R2.Component SubmitButtonProps
submitButton = R.createElement submitButtonComponent
submitButtonComponent :: R.Component SubmitButtonProps
submitButtonComponent = here.component "submitButton" cpt
where
cpt { onSearch, search, session } _ = do
cpt { errors, onSearch, search, session } _ = do
search' <- T.useLive T.unequal search
pure $
H.button { className: "btn btn-primary"
, "type" : "button"
, on : { click: doSearch onSearch session search' }
, on : { click: doSearch onSearch errors session search' }
, style : { width: "100%" }
} [ H.text "Launch Search" ]
doSearch os s q = \_ -> do
doSearch os errors s q = \_ -> do
log2 "[submitButton] searching" q
triggerSearch os s q
triggerSearch os errors s q
--case search.term of
-- "" -> setSearch $ const defaultSearch
-- _ -> setSearch $ const q
triggerSearch :: (GT.AsyncTaskWithType -> Effect Unit)
-> T.Box (Array FrontendError)
-> Session
-> Search
-> Effect Unit
triggerSearch os s q =
triggerSearch os errors s q =
launchAff_ $ do
liftEffect $ do
let here' = "[triggerSearch] Searching "
......@@ -473,8 +469,8 @@ triggerSearch os s q =
case q.node_id of
Nothing -> liftEffect $ log "[triggerSearch] node_id is Nothing, don't know what to do"
Just id -> do
task <- performSearch s id $ searchQuery q
liftEffect $ do
eTask <- performSearch s id $ searchQuery q
handleRESTError errors eTask $ \task -> liftEffect $ do
log2 "[triggerSearch] task" task
os task
......
module Gargantext.Components.Forest.Tree.Node.Action.Search.Types where
import Control.Monad.Error.Class (throwError)
import Data.Array (concat)
import Data.Either (Either(..))
import Data.Either (Either)
import Data.Generic.Rep (class Generic)
import Data.Maybe (Maybe(..), fromMaybe, maybe)
import Data.Newtype (class Newtype)
......@@ -11,8 +10,7 @@ import Data.Set as Set
import Data.String as String
import Data.Tuple (Tuple)
import Data.Tuple.Nested ((/\))
import Effect.Aff (Aff, error)
import Effect.Class (liftEffect)
import Effect.Aff (Aff)
import Simple.JSON as JSON
import URI.Extra.QueryPairs as QP
import URI.Query as Q
......@@ -363,18 +361,16 @@ instance GT.ToQuery SearchQuery where
pair k = maybe [] $ \v ->
[ QP.keyFromString k /\ Just (QP.valueFromString $ show v) ]
instance JSON.WriteForeign SearchQuery where
writeImpl (SearchQuery { datafield, databases, lang, node_id, query }) =
writeImpl (SearchQuery { databases, lang, node_id, query }) =
JSON.writeImpl { query: String.replace (String.Pattern "\"") (String.Replacement "\\\"") query
, databases: databases
, lang: maybe "EN" show lang
, node_id: fromMaybe 0 node_id
}
performSearch :: Session -> Int -> SearchQuery -> Aff GT.AsyncTaskWithType
performSearch :: Session -> Int -> SearchQuery -> Aff (Either RESTError GT.AsyncTaskWithType)
performSearch session nodeId q = do
eTask :: Either RESTError GT.AsyncTask <- post session p q
case eTask of
Left _err -> liftEffect $ throwError $ error "[performSearch] RESTError"
Right task -> pure $ GT.AsyncTaskWithType { task, typ: GT.Query }
pure $ (\task -> GT.AsyncTaskWithType { task, typ: GT.Query }) <$> eTask
where
p = GR.NodeAPI GT.Corpus (Just nodeId) $ GT.asyncTaskTypePath GT.Query
module Gargantext.Components.Forest.Tree.Node.Action.Update where
import Control.Monad.Error.Class (throwError)
import Data.Either (Either(..))
import Data.Maybe (Maybe(..))
import Effect.Aff (Aff)
import Effect.Class (liftEffect)
import Effect.Exception (error)
import Reactix as R
import Reactix.DOM.HTML as H
import Toestand as T
......@@ -25,12 +22,12 @@ import Gargantext.Utils.Reactix as R2
here :: R2.Here
here = R2.here "Gargantext.Components.Forest.Tree.Node.Action.Update"
updateRequest :: UpdateNodeParams -> Session -> ID -> Aff GT.AsyncTaskWithType
updateRequest :: UpdateNodeParams -> Session -> ID -> Aff (Either RESTError GT.AsyncTaskWithType)
updateRequest updateNodeParams session nodeId = do
eTask :: Either RESTError GT.AsyncTask <- post session p updateNodeParams
case eTask of
Left _err -> liftEffect $ throwError $ error "[updateRequest] RESTError"
Right task -> pure $ GT.AsyncTaskWithType { task, typ: GT.UpdateNode }
Left err -> pure $ Left err
Right task -> pure $ Right $ GT.AsyncTaskWithType { task, typ: GT.UpdateNode }
where
p = GR.NodeAPI GT.Node (Just nodeId) "update"
......
......@@ -2,8 +2,6 @@ module Gargantext.Components.Forest.Tree.Node.Action.Upload where
import Gargantext.Prelude
import Control.Monad.Error.Class (throwError)
import DOM.Simple.Console (log2)
import Data.Either (Either(..), fromRight')
import Data.Eq.Generic (genericEq)
import Data.Generic.Rep (class Generic)
......@@ -16,7 +14,6 @@ import Data.Tuple.Nested ((/\))
import Effect (Effect)
import Effect.Aff (Aff, launchAff)
import Effect.Class (liftEffect)
import Effect.Exception (error)
import Gargantext.Components.Forest.Tree.Node.Action (Action(..), Props)
import Gargantext.Components.Forest.Tree.Node.Action.Upload.Types (FileType(..), UploadFileBlob(..), readUFBAsText)
import Gargantext.Components.Forest.Tree.Node.Tools (fragmentPT, formChoiceSafe, panel)
......@@ -86,7 +83,7 @@ type UploadFile =
}
uploadFileView :: Record Props -> R.Element
uploadFileView :: R2.Leaf Props
uploadFileView props = R.createElement uploadFileViewCpt props []
uploadFileViewCpt :: R.Component Props
uploadFileViewCpt = here.component "uploadFileView" cpt
......@@ -191,7 +188,7 @@ uploadButtonCpt = here.component "uploadButton" cpt
where
onClick fileType' mFile' e = do
let { blob, name } = unsafePartial $ fromJust mFile'
log2 "[uploadButton] fileType" fileType'
here.log2 "[uploadButton] fileType" fileType'
void $ launchAff do
case fileType' of
Arbitrary ->
......@@ -306,12 +303,13 @@ instance GT.ToQuery FileUploadQuery where
where pair :: forall a. Show a => String -> a -> Array (Tuple QP.Key (Maybe QP.Value))
pair k v = [ QP.keyFromString k /\ (Just $ QP.valueFromString $ show v) ]
uploadFile :: Session
-> GT.NodeType
-> ID
-> FileType
-> {contents :: String, mName :: Maybe String}
-> Aff GT.AsyncTaskWithType
uploadFile :: { contents :: String
, fileType :: FileType
, id :: ID
, nodeType :: GT.NodeType
, mName :: Maybe String
, session :: Session }
-> Aff (Either RESTError GT.AsyncTaskWithType)
{-
uploadFile session NodeList id JSON { mName, contents } = do
let url = GR.NodeAPI NodeList (Just id) $ GT.asyncTaskTypePath GT.ListUpload
......@@ -322,12 +320,12 @@ uploadFile session NodeList id JSON { mName, contents } = do
task <- post session url body
pure $ GT.AsyncTaskWithType { task, typ: GT.Form }
-}
uploadFile session nodeType id fileType { mName, contents } = do
uploadFile { contents, fileType, id, nodeType, mName, session } = do
-- contents <- readAsText blob
eTask :: Either RESTError GT.AsyncTask <- postWwwUrlencoded session p bodyParams
case eTask of
Left _err -> liftEffect $ throwError $ error "[uploadFile] RESTError"
Right task -> pure $ GT.AsyncTaskWithType { task, typ: GT.Form }
Left err -> pure $ Left err
Right task -> pure $ Right $ GT.AsyncTaskWithType { task, typ: GT.Form }
--postMultipartFormData session p fileContents
where
p = case nodeType of
......
......@@ -5,7 +5,7 @@ import Gargantext.Prelude
import Data.Array as A
import Data.Maybe (Maybe(..))
import Effect.Aff (Aff)
import Gargantext.Components.Forest.Tree.Node.Action (Action(..))
import Gargantext.Components.Forest.Tree.Node.Action (Action)
import Gargantext.Components.Forest.Tree.Node.Action.Add (NodePopup(..), addNodeView)
import Gargantext.Components.Forest.Tree.Node.Action.Contact as Contact
import Gargantext.Components.Forest.Tree.Node.Action.Delete (actionDelete)
......@@ -22,9 +22,9 @@ import Gargantext.Components.Forest.Tree.Node.Action.Upload (actionUpload)
import Gargantext.Components.Forest.Tree.Node.Box.Types (NodePopupProps, NodePopupS)
import Gargantext.Components.Forest.Tree.Node.Settings (NodeAction(..), SettingsBox(..), glyphiconNodeAction, settingsBox)
import Gargantext.Components.Forest.Tree.Node.Status (Status(..), hasStatus)
import Gargantext.Components.Forest.Tree.Node.Tools (textInputBox, fragmentPT, panel)
import Gargantext.Components.Forest.Tree.Node.Tools (textInputBox, fragmentPT)
import Gargantext.Sessions (Session)
import Gargantext.Types (Name, ID, prettyNodeType)
import Gargantext.Types (FrontendError, ID, Name, prettyNodeType)
import Gargantext.Types as GT
import Gargantext.Utils.Glyphicon (glyphicon, glyphiconActive)
import Gargantext.Utils.Reactix as R2
......@@ -35,11 +35,12 @@ import Toestand as T
here :: R2.Here
here = R2.here "Gargantext.Components.Forest.Tree.Node.Box"
type CommonProps = ( dispatch :: Action -> Aff Unit, session :: Session )
type CommonProps =
( dispatch :: Action -> Aff Unit
, session :: Session )
nodePopupView :: Record NodePopupProps -> R.Element
nodePopupView p = R.createElement nodePopupCpt p []
nodePopupCpt :: R.Component NodePopupProps
nodePopupCpt = here.component "nodePopupView" cpt where
cpt p@{ id, name, nodeType } _ = do
......@@ -101,8 +102,8 @@ nodePopupCpt = here.component "nodePopupView" cpt where
else []
mPanelAction :: Record NodePopupS -> Record NodePopupProps -> R.Element
mPanelAction { action: Just action }
{ dispatch, id, name, nodeType, session, handed } =
panelAction { action, dispatch, id, name, nodeType, session
{ dispatch, errors, id, name, nodeType, session, handed } =
panelAction { action, dispatch, errors, id, name, nodeType, session
, handed, nodePopup: Just NodePopup }
mPanelAction { action: Nothing } _ =
H.div { className: "card-footer" }
......@@ -162,6 +163,7 @@ type PanelActionProps =
( id :: ID
, action :: NodeAction
, dispatch :: Action -> Aff Unit
, errors :: T.Box (Array FrontendError)
, name :: Name
, nodePopup :: Maybe NodePopup
, nodeType :: GT.NodeType
......@@ -169,9 +171,8 @@ type PanelActionProps =
, handed :: GT.Handed
)
panelAction :: Record PanelActionProps -> R.Element
panelAction :: R2.Leaf PanelActionProps
panelAction p = R.createElement panelActionCpt p []
panelActionCpt :: R.Component PanelActionProps
panelActionCpt = here.component "panelAction" cpt
where
......@@ -195,6 +196,6 @@ panelActionCpt = here.component "panelAction" cpt
cpt {action : AddingContact, dispatch, id, name } _ = pure $ Contact.actionAddContact { dispatch, id } []
cpt {action : Publish {subTreeParams}, dispatch, id, nodeType, session, handed} _ =
pure $ Share.publishNode { dispatch, handed, id, nodeType, session, subTreeParams } []
cpt props@{action: SearchBox, id, session, dispatch, nodePopup} _ =
pure $ actionSearch { dispatch, id: (Just id), nodePopup, session } []
cpt props@{action: SearchBox, errors, id, session, dispatch, nodePopup} _ =
pure $ actionSearch { dispatch, errors, id: (Just id), nodePopup, session } []
cpt _ _ = pure $ H.div {} []
......@@ -4,12 +4,13 @@ import DOM.Simple as DOM
import Data.Maybe (Maybe)
import Effect (Effect)
import Effect.Aff (Aff)
import Gargantext.Components.Forest.Tree.Node.Settings (NodeAction)
import Gargantext.Components.Forest.Tree.Node.Action (Action)
import Gargantext.Components.Forest.Tree.Node.Settings (NodeAction)
import Gargantext.Prelude (Unit)
import Gargantext.Sessions (Session)
import Gargantext.Types (ID, Name)
import Gargantext.Types (FrontendError, ID, Name)
import Gargantext.Types as GT
import Toestand as T
type CommonProps =
( dispatch :: Action -> Aff Unit
......@@ -18,7 +19,8 @@ type CommonProps =
)
type NodePopupProps =
( id :: ID
( errors :: T.Box (Array FrontendError)
, id :: ID
, name :: Name
, nodeType :: GT.NodeType
, onPopoverClose :: DOM.Element -> Effect Unit
......
......@@ -2,18 +2,18 @@ module Gargantext.Components.Forest.Tree.Node.Tools.ProgressBar where
import Gargantext.Prelude
import Control.Monad.Error.Class (throwError)
import Data.Either (Either(..))
import Data.Either (Either)
import Data.Int (fromNumber)
import Data.Maybe (Maybe(..))
import Data.Tuple.Nested ((/\))
import Effect (Effect)
import Effect.Aff (Aff, error, launchAff_)
import Effect.Aff (Aff, launchAff_)
import Effect.Class (liftEffect)
import Effect.Timer (clearInterval, setInterval)
import Gargantext.Config.REST (RESTError)
import Gargantext.Config.Utils (handleRESTError)
import Gargantext.Routes (SessionRoute(..))
import Gargantext.Sessions (Session, get)
import Gargantext.Types (FrontendError)
import Gargantext.Types as GT
import Gargantext.Utils.Reactix as R2
import Reactix as R
......@@ -29,6 +29,7 @@ data BarType = Bar | Pie
type Props = (
asyncTask :: GT.AsyncTaskWithType
, barType :: BarType
, errors :: T.Box (Array FrontendError)
, nodeId :: GT.ID
, onFinish :: Unit -> Effect Unit
, session :: Session
......@@ -42,6 +43,7 @@ asyncProgressBarCpt = here.component "asyncProgressBar" cpt
where
cpt props@{ asyncTask: (GT.AsyncTaskWithType {task: GT.AsyncTask {id}})
, barType
, errors
, onFinish
} _ = do
progress <- T.useBox 0.0
......@@ -51,19 +53,16 @@ asyncProgressBarCpt = here.component "asyncProgressBar" cpt
intervalId <- setInterval 1000 $ do
launchAff_ $ do
eAsyncProgress <- queryProgress props
case eAsyncProgress of
Left _err -> throwError $ error "[asyncProgressBar] RESTError"
Right asyncProgress -> do
let GT.AsyncProgress { status } = asyncProgress
liftEffect do
T.write_ (min 100.0 $ GT.progressPercent asyncProgress) progress
if (status == GT.IsFinished) || (status == GT.IsKilled) || (status == GT.IsFailure) then do
_ <- case R.readRef intervalIdRef of
Nothing -> pure unit
Just iid -> clearInterval iid
onFinish unit
else
pure unit
handleRESTError errors eAsyncProgress $ \asyncProgress -> liftEffect $ do
let GT.AsyncProgress { status } = asyncProgress
T.write_ (min 100.0 $ GT.progressPercent asyncProgress) progress
if (status == GT.IsFinished) || (status == GT.IsKilled) || (status == GT.IsFailure) then do
_ <- case R.readRef intervalIdRef of
Nothing -> pure unit
Just iid -> clearInterval iid
onFinish unit
else
pure unit
R.setRef intervalIdRef $ Just intervalId
......
......@@ -4,9 +4,8 @@ module Gargantext.Components.Nodes.Annuaire.Tabs where
import Prelude hiding (div)
import Data.Generic.Rep (class Generic)
import Data.Show.Generic (genericShow)
import Data.Maybe (Maybe(..))
import Data.Tuple (fst)
import Data.Show.Generic (genericShow)
import Data.Tuple.Nested ((/\))
import Effect.Aff (Aff)
import Gargantext.AsyncTasks as GAT
......@@ -16,12 +15,11 @@ import Gargantext.Components.NgramsTable as NT
import Gargantext.Components.NgramsTable.Core as NTC
import Gargantext.Components.Nodes.Annuaire.User.Contacts.Types (ContactData)
import Gargantext.Components.Nodes.Lists.Types as LTypes
import Gargantext.Components.Nodes.Texts.Types as TTypes
import Gargantext.Components.Nodes.Texts.Types as TextsT
import Gargantext.Components.Tab as Tab
import Gargantext.Ends (Frontends)
import Gargantext.Sessions (Session)
import Gargantext.Types (CTabNgramType(..), PTabNgramType(..), SidePanelState, TabType(..), TabSubType(..))
import Gargantext.Types (CTabNgramType(..), FrontendError, PTabNgramType(..), SidePanelState, TabSubType(..), TabType(..))
import Gargantext.Utils.Reactix as R2
import Gargantext.Utils.Toestand as T2
import Reactix as R
......@@ -55,6 +53,7 @@ modeTabType' Communication = CTabAuthors
type TabsProps =
( cacheState :: T.Box LTypes.CacheState
, contactData :: ContactData
, errors :: T.Box (Array FrontendError)
, frontends :: Frontends
, nodeId :: Int
, reloadForest :: T2.ReloadS
......@@ -89,6 +88,7 @@ tabsCpt = here.component "tabs" cpt where
dtCommon = RX.pick props :: Record DTCommon
dtExtra =
{ chart: mempty
, errors: props.errors
, listId: props.contactData.defaultListId
, mCorpusId: Nothing
, showSearch: true
......
......@@ -23,7 +23,7 @@ import Gargantext.Ends (Frontends)
import Gargantext.Hooks.Loader (useLoader)
import Gargantext.Routes as Routes
import Gargantext.Sessions (WithSession, WithSessionContext, Session, get, put, sessionId)
import Gargantext.Types (NodeType(..), SidePanelState)
import Gargantext.Types (FrontendError, NodeType(..), SidePanelState)
import Gargantext.Utils.Reactix as R2
import Gargantext.Utils.Toestand as T2
import Reactix as R
......@@ -153,7 +153,8 @@ listElement = H.li { className: "list-group-item justify-content-between" }
-}
type LayoutNoSessionProps =
( frontends :: Frontends
( errors :: T.Box (Array FrontendError)
, frontends :: Frontends
, nodeId :: Int
, reloadForest :: T2.ReloadS
, reloadRoot :: T2.ReloadS
......@@ -176,7 +177,8 @@ userLayout = R.createElement userLayoutCpt
userLayoutCpt :: R.Component LayoutProps
userLayoutCpt = here.component "userLayout" cpt
where
cpt { frontends
cpt { errors
, frontends
, nodeId
, reloadForest
, reloadRoot
......@@ -187,7 +189,8 @@ userLayoutCpt = here.component "userLayout" cpt
let sid = sessionId session
pure $ userLayoutWithKey {
frontends
errors
, frontends
, key: show sid <> "-" <> show nodeId
, nodeId
, reloadForest
......@@ -198,52 +201,53 @@ userLayoutCpt = here.component "userLayout" cpt
, tasks
}
userLayoutWithKey :: Record KeyLayoutProps -> R.Element
userLayoutWithKey :: R2.Leaf KeyLayoutProps
userLayoutWithKey props = R.createElement userLayoutWithKeyCpt props []
userLayoutWithKeyCpt :: R.Component KeyLayoutProps
userLayoutWithKeyCpt = here.component "userLayoutWithKey" cpt
where
cpt { frontends
, nodeId
, reloadForest
, reloadRoot
, session
, sidePanel
, sidePanelState
, tasks } _ = do
reload <- T.useBox T2.newReload
reload' <- T.useLive T.unequal reload
userLayoutWithKeyCpt = here.component "userLayoutWithKey" cpt where
cpt { errors
, frontends
, nodeId
, reloadForest
, reloadRoot
, session
, sidePanel
, sidePanelState
, tasks } _ = do
reload <- T.useBox T2.newReload
reload' <- T.useLive T.unequal reload
cacheState <- T.useBox LT.CacheOn
cacheState <- T.useBox LT.CacheOn
useLoader { errorHandler
, loader: getUserWithReload
, path: { nodeId, reload: reload', session }
, render: \contactData@{contactNode: Contact {name, hyperdata}} ->
H.ul { className: "col-md-12 list-group" } [
display { title: fromMaybe "no name" name }
(contactInfos hyperdata (onUpdateHyperdata reload))
useLoader { errorHandler
, loader: getUserWithReload
, path: { nodeId, reload: reload', session }
, render: \contactData@{contactNode: Contact {name, hyperdata}} ->
H.ul { className: "col-md-12 list-group" } [
display { title: fromMaybe "no name" name }
(contactInfos hyperdata (onUpdateHyperdata reload))
, Tabs.tabs {
cacheState
, contactData
, frontends
, nodeId
, reloadForest
, reloadRoot
, session
, sidePanel
, sidePanelState
, tasks
}
cacheState
, contactData
, errors
, frontends
, nodeId
, reloadForest
, reloadRoot
, session
, sidePanel
, sidePanelState
, tasks
}
]
}
where
errorHandler err = here.log2 "[userLayoutWithKey] RESTError" err
onUpdateHyperdata :: T2.ReloadS -> HyperdataUser -> Effect Unit
onUpdateHyperdata reload hd = do
launchAff_ $ do
_ <- saveContactHyperdata session nodeId hd
liftEffect $ T2.reload reload
}
where
errorHandler err = here.log2 "[userLayoutWithKey] RESTError" err
onUpdateHyperdata :: T2.ReloadS -> HyperdataUser -> Effect Unit
onUpdateHyperdata reload hd = do
launchAff_ $ do
_ <- saveContactHyperdata session nodeId hd
liftEffect $ T2.reload reload
-- | toUrl to get data XXX
getContact :: Session -> Int -> Aff (Either RESTError ContactData)
......
......@@ -3,28 +3,18 @@ module Gargantext.Components.Nodes.Annuaire.User.Contact
, contactLayout
) where
import Gargantext.Prelude
import Data.Either (Either)
import Data.Lens as L
import Data.Maybe (Maybe(..), fromMaybe)
import Effect (Effect)
import Effect.Aff (Aff, launchAff_)
import Effect.Class (liftEffect)
import Reactix as R
import Reactix.DOM.HTML as H
import Toestand as T
import Gargantext.Prelude
import Gargantext.AsyncTasks as GAT
import Gargantext.Components.InputWithEnter (inputWithEnter)
import Gargantext.Components.Nodes.Annuaire.User.Contacts.Tabs as Tabs
import Gargantext.Components.Nodes.Annuaire.User.Contacts.Types
( Contact'(..), ContactData', ContactTouch(..), ContactWhere(..)
, ContactWho(..), HyperdataContact(..), HyperdataUser(..)
, _city, _country, _firstName, _labTeamDeptsJoinComma, _lastName
, _mail, _office, _organizationJoinComma, _ouFirst, _phone, _role
, _shared, _touch, _who, defaultContactTouch, defaultContactWhere
, defaultContactWho, defaultHyperdataContact, defaultHyperdataUser )
import Gargantext.Components.Nodes.Annuaire.User.Contacts.Types (Contact'(..), ContactData', ContactTouch(..), ContactWhere(..), ContactWho(..), HyperdataContact(..), HyperdataUser(..), _city, _country, _firstName, _labTeamDeptsJoinComma, _lastName, _mail, _office, _organizationJoinComma, _ouFirst, _phone, _role, _shared, _touch, _who, defaultContactTouch, defaultContactWhere, defaultContactWho, defaultHyperdataContact, defaultHyperdataUser)
import Gargantext.Components.Nodes.Lists.Types as LT
import Gargantext.Components.Nodes.Texts.Types as TT
import Gargantext.Config.REST (RESTError)
......@@ -32,9 +22,12 @@ import Gargantext.Ends (Frontends)
import Gargantext.Hooks.Loader (useLoader)
import Gargantext.Routes as Routes
import Gargantext.Sessions (Session, get, put, sessionId)
import Gargantext.Types (NodeType(..), SidePanelState)
import Gargantext.Types (FrontendError, NodeType(..), SidePanelState)
import Gargantext.Utils.Reactix as R2
import Gargantext.Utils.Toestand as T2
import Reactix as R
import Reactix.DOM.HTML as H
import Toestand as T
here :: R2.Here
here = R2.here "Gargantext.Components.Nodes.Annuaire.User.Contact"
......@@ -43,7 +36,6 @@ type DisplayProps = ( title :: String )
display :: R2.Component DisplayProps
display = R.createElement displayCpt
displayCpt :: R.Component DisplayProps
displayCpt = here.component "display" cpt
where
......@@ -140,7 +132,8 @@ contactInfoItemCpt = here.component "contactInfoItem" cpt
onUpdateHyperdata newHyperdata
type BasicProps =
( frontends :: Frontends
( errors :: T.Box (Array FrontendError)
, frontends :: Frontends
, nodeId :: Int
, sidePanelState :: T.Box SidePanelState
, sidePanel :: T.Box (Maybe (Record TT.SidePanel))
......@@ -166,10 +159,10 @@ type AnnuaireKeyLayoutProps = ( annuaireId :: Int | KeyLayoutProps )
contactLayout :: R2.Component AnnuaireLayoutProps
contactLayout = R.createElement contactLayoutCpt
contactLayoutCpt :: R.Component AnnuaireLayoutProps
contactLayoutCpt = here.component "contactLayout" cpt where
cpt { annuaireId
, errors
, frontends
, nodeId
, reloadForest
......@@ -182,6 +175,7 @@ contactLayoutCpt = here.component "contactLayout" cpt where
pure $
contactLayoutWithKey
{ annuaireId
, errors
, frontends
, key
, nodeId
......@@ -198,6 +192,7 @@ contactLayoutWithKey props = R.createElement contactLayoutWithKeyCpt props []
contactLayoutWithKeyCpt :: R.Component AnnuaireKeyLayoutProps
contactLayoutWithKeyCpt = here.component "contactLayoutWithKey" cpt where
cpt { annuaireId
, errors
, frontends
, reloadForest
, reloadRoot
......@@ -219,6 +214,7 @@ contactLayoutWithKeyCpt = here.component "contactLayoutWithKey" cpt where
, Tabs.tabs
{ cacheState
, contactData
, errors
, frontends
, nodeId
, session
......
-- TODO copy of Gargantext.Components.Nodes.Corpus.Tabs.Specs
module Gargantext.Components.Nodes.Annuaire.User.Contacts.Tabs where
import Prelude hiding (div)
import Gargantext.Prelude
import Data.Generic.Rep (class Generic)
import Data.Show.Generic (genericShow)
import Data.Maybe (Maybe(..))
import Data.Tuple (fst)
import Data.Show.Generic (genericShow)
import Data.Tuple.Nested ((/\))
import Gargantext.AsyncTasks as GAT
import Gargantext.Components.DocsTable as DT
......@@ -19,7 +18,7 @@ import Gargantext.Components.Nodes.Texts.Types as TTypes
import Gargantext.Components.Tab as Tab
import Gargantext.Ends (Frontends)
import Gargantext.Sessions (Session)
import Gargantext.Types (CTabNgramType(..), PTabNgramType(..), SidePanelState, TabType(..), TabSubType(..))
import Gargantext.Types (CTabNgramType(..), FrontendError, PTabNgramType(..), SidePanelState, TabSubType(..), TabType(..))
import Gargantext.Utils.Reactix as R2
import Gargantext.Utils.Toestand as T2
import Reactix as R
......@@ -52,6 +51,7 @@ modeTabType' Communication = CTabAuthors
type TabsProps = (
cacheState :: T.Box LTypes.CacheState
, contactData :: ContactData'
, errors :: T.Box (Array FrontendError)
, frontends :: Frontends
, nodeId :: Int
, reloadForest :: T2.ReloadS
......@@ -62,22 +62,23 @@ type TabsProps = (
, tasks :: T.Box GAT.Storage
)
tabs :: Record TabsProps -> R.Element
tabs :: R2.Leaf TabsProps
tabs props = R.createElement tabsCpt props []
tabsCpt :: R.Component TabsProps
tabsCpt = here.component "tabs" cpt
where
cpt { reloadRoot
, tasks
, cacheState
cpt { cacheState
, contactData: {defaultListId}
, errors
, frontends
, nodeId
, reloadRoot
, reloadForest
, session
, sidePanel
, sidePanelState
, reloadForest } _ = do
, tasks
} _ = do
activeTab <- T.useBox 0
yearFilter <- T.useBox (Nothing :: Maybe Year)
......@@ -119,6 +120,7 @@ tabsCpt = here.component "tabs" cpt
docs = DT.docViewLayout
{ cacheState
, chart
, errors
, frontends
, listId: defaultListId
, mCorpusId: Nothing
......
module Gargantext.Components.Nodes.Corpus where
import DOM.Simple.Console (log2)
import Data.Array as A
import Data.Either (Either(..))
import Data.Eq.Generic (genericEq)
......@@ -7,16 +8,10 @@ import Data.Generic.Rep (class Generic)
import Data.List as List
import Data.Maybe (Maybe(..), fromMaybe)
import Data.Show.Generic (genericShow)
import DOM.Simple.Console (log2)
import Effect (Effect)
import Effect.Aff (Aff, launchAff_, throwError)
import Effect.Class (liftEffect)
import Effect.Exception (error)
import Reactix as R
import Reactix.DOM.HTML as H
import Simple.JSON as JSON
import Toestand as T
import Gargantext.AsyncTasks as GAT
import Gargantext.Components.CodeEditor as CE
import Gargantext.Components.FolderView as FV
......@@ -30,41 +25,49 @@ import Gargantext.Hooks.Loader (useLoader)
import Gargantext.Prelude (class Eq, class Show, Unit, bind, discard, pure, show, unit, ($), (+), (-), (<), (<$>), (<<<), (<>), (==), (>))
import Gargantext.Routes (SessionRoute(Children, NodeAPI))
import Gargantext.Sessions (Session, get, put, sessionId)
import Gargantext.Types (AffETableResult, NodeType(..))
import Gargantext.Types (AffETableResult, FrontendError, NodeType(..))
import Gargantext.Utils.Crypto as Crypto
import Gargantext.Utils.Reactix as R2
import Gargantext.Utils.Toestand as T2
import Reactix as R
import Reactix.DOM.HTML as H
import Simple.JSON as JSON
import Toestand as T
here :: R2.Here
here = R2.here "Gargantext.Components.Nodes.Corpus"
type Props = ( nodeId :: Int, session :: Session, tasks :: T.Box GAT.Storage, reloadForest :: T2.ReloadS )
type Props =
( errors :: T.Box (Array FrontendError)
, nodeId :: Int
, reloadForest :: T2.ReloadS
, session :: Session
, tasks :: T.Box GAT.Storage )
corpusLayout :: R2.Leaf Props
corpusLayout props = R.createElement corpusLayoutCpt props []
corpusLayoutCpt :: R.Component Props
corpusLayoutCpt = here.component "corpusLayout" cpt where
cpt { nodeId, session, tasks, reloadForest } _ = do
pure $ corpusLayoutMain { key, nodeId, session, tasks, reloadForest }
cpt { errors, nodeId, session, tasks, reloadForest } _ = do
pure $ corpusLayoutMain { errors, key, nodeId, session, tasks, reloadForest }
where
key = show (sessionId session) <> "-" <> show nodeId
type KeyProps =
( nodeId :: Int
( errors :: T.Box (Array FrontendError)
, key :: String
, nodeId :: Int
, reloadForest :: T2.ReloadS
, session :: Session
, tasks :: T.Box GAT.Storage
, reloadForest :: T2.ReloadS
)
corpusLayoutMain :: R2.Leaf KeyProps
corpusLayoutMain props = R.createElement corpusLayoutMainCpt props []
corpusLayoutMainCpt :: R.Component KeyProps
corpusLayoutMainCpt = here.component "corpusLayoutMain" cpt
where
cpt { nodeId, key, session, tasks, reloadForest } _ = do
cpt { errors, nodeId, key, session, tasks, reloadForest } _ = do
viewType <- T.useBox Folders
pure $ H.div {} [
......@@ -74,11 +77,12 @@ corpusLayoutMainCpt = here.component "corpusLayoutMain" cpt
, H.div { className: "col-1" } [ FV.homeButton ]
]
]
, H.div {} [corpusLayoutSelection {state: viewType, key, session, nodeId, tasks, reloadForest}]
, H.div {} [corpusLayoutSelection { errors, state: viewType, key, session, nodeId, tasks, reloadForest }]
]
type SelectionProps =
( nodeId :: Int
( errors :: T.Box (Array FrontendError)
, nodeId :: Int
, key :: String
, session :: Session
, state :: T.Box ViewType
......@@ -88,17 +92,17 @@ type SelectionProps =
corpusLayoutSelection :: R2.Leaf SelectionProps
corpusLayoutSelection props = R.createElement corpusLayoutSelectionCpt props []
corpusLayoutSelectionCpt :: R.Component SelectionProps
corpusLayoutSelectionCpt = here.component "corpusLayoutSelection" cpt where
cpt { nodeId, session, key, state, tasks, reloadForest} _ = do
cpt { errors, nodeId, session, key, state, tasks, reloadForest} _ = do
state' <- T.useLive T.unequal state
viewType <- T.read state
pure $ renderContent viewType nodeId session key tasks reloadForest
pure $ renderContent viewType nodeId session key tasks reloadForest errors
renderContent Folders nodeId session key tasks reloadForest = FV.folderView { nodeId, session, backFolder: true, tasks, reloadForest }
renderContent Code nodeId session key tasks _ = corpusLayoutWithKey { key, nodeId, session }
renderContent Folders nodeId session key tasks reloadForest errors =
FV.folderView { errors, nodeId, session, backFolder: true, tasks, reloadForest }
renderContent Code nodeId session key tasks _ _ = corpusLayoutWithKey { key, nodeId, session }
type CorpusKeyProps =
( nodeId :: Int
......@@ -108,7 +112,6 @@ type CorpusKeyProps =
corpusLayoutWithKey :: R2.Leaf CorpusKeyProps
corpusLayoutWithKey props = R.createElement corpusLayoutWithKeyCpt props []
corpusLayoutWithKeyCpt :: R.Component CorpusKeyProps
corpusLayoutWithKeyCpt = here.component "corpusLayoutWithKey" cpt where
cpt { nodeId, session } _ = do
......
module Gargantext.Components.Nodes.Corpus.Chart.Common where
import Gargantext.Prelude
import Data.Array as A
import Data.Either (Either)
import Data.Tuple.Nested ((/\))
import Effect.Aff (Aff)
import Reactix as R
import Simple.JSON as JSON
import Toestand as T
import Gargantext.Prelude
import Gargantext.Components.Nodes.Corpus.Chart.Types (MetricsProps, ReloadPath)
import Gargantext.Config.REST (RESTError)
import Gargantext.Hooks.Loader (HashedResponse, useLoader, useLoaderWithCacheAPI)
import Gargantext.Utils.Crypto (Hash)
import Gargantext.Sessions (Session)
import Gargantext.Types (FrontendError(..))
import Gargantext.Utils.CacheAPI as GUC
import Gargantext.Utils.Crypto (Hash)
import Gargantext.Utils.Reactix as R2
import Reactix as R
import Simple.JSON as JSON
import Toestand as T
here :: R2.Here
here = R2.here "Gargantext.Components.Nodes.Corpus.Chart.Common"
......@@ -34,21 +35,23 @@ metricsLoadView p = R.createElement metricsLoadViewCpt p []
metricsLoadViewCpt :: forall a. Eq a => R.Component (MetricsLoadViewProps a)
metricsLoadViewCpt = here.component "metricsLoadView" cpt
where
cpt { getMetrics, loaded, path, reload, session, onClick, onInit } _ = do
cpt { errors, getMetrics, loaded, onClick, onInit, path, reload, session } _ = do
reload' <- T.useLive T.unequal reload
useLoader { errorHandler
, loader: getMetrics session
, path: reload' /\ path
, render: \l -> loaded { path, reload, session, onClick, onInit } l }
, render: \l -> loaded { errors, path, reload, session, onClick, onInit } l }
where
errorHandler err = here.log2 "RESTError" err
errorHandler error = do
T.modify_ (A.cons $ FRESTError { error }) errors
here.log2 "RESTError" error
type MetricsWithCacheLoadViewProps res ret = (
getMetricsHash :: Session -> ReloadPath -> Aff (Either RESTError Hash)
type MetricsWithCacheLoadViewProps res ret =
( getMetricsHash :: Session -> ReloadPath -> Aff (Either RESTError Hash)
, handleResponse :: HashedResponse res -> ret
, loaded :: Record MetricsProps -> ret -> R.Element
, mkRequest :: ReloadPath -> GUC.Request
, loaded :: Record MetricsProps -> ret -> R.Element
, mkRequest :: ReloadPath -> GUC.Request
| MetricsProps
)
......@@ -61,11 +64,21 @@ metricsWithCacheLoadViewCpt :: forall res ret.
R.Component (MetricsWithCacheLoadViewProps res ret)
metricsWithCacheLoadViewCpt = here.component "metricsWithCacheLoadView" cpt
where
cpt { getMetricsHash, handleResponse, loaded, mkRequest, path, reload, session, onClick, onInit } _ = do
cpt { errors
, getMetricsHash
, handleResponse
, loaded
, mkRequest
, path
, reload
, session
, onClick
, onInit } _ = do
reload' <- T.useLive T.unequal reload
useLoaderWithCacheAPI { cacheEndpoint: (getMetricsHash session)
, errors
, handleResponse
, mkRequest
, path: (reload' /\ path)
, renderer: loaded { path, reload, session, onClick, onInit } }
, renderer: loaded { errors, path, reload, session, onClick, onInit } }
......@@ -95,15 +95,15 @@ mkRequest session (_ /\ path) = GUC.makeGetRequest session $ chartUrl path
histo :: Record Props -> R.Element
histo props = R.createElement histoCpt props []
histoCpt :: R.Component Props
histoCpt = here.component "histo" cpt
where
cpt { path, session, onClick, onInit } _ = do
cpt { errors, path, session, onClick, onInit } _ = do
reload <- T.useBox T2.newReload
pure $ metricsWithCacheLoadView {
getMetricsHash
errors
, getMetricsHash
, handleResponse
, loaded
, mkRequest: mkRequest session
......
......@@ -110,15 +110,15 @@ mkRequest session (_ /\ path) = GUC.makeGetRequest session $ chartUrl path
metrics :: Record Props -> R.Element
metrics props = R.createElement metricsCpt props []
metricsCpt :: R.Component Props
metricsCpt = here.component "etrics" cpt
where
cpt {path, session, onClick, onInit } _ = do
cpt { errors, onClick, onInit, path, session } _ = do
reload <- T.useBox T2.newReload
pure $ metricsWithCacheLoadView {
getMetricsHash
errors
, getMetricsHash
, handleResponse
, loaded
, mkRequest: mkRequest session
......
......@@ -85,7 +85,7 @@ chartOptionsPie { onClick, onInit } (HistoMetrics { dates: dates', count: count'
}
getMetricsHash :: Session -> ReloadPath -> Aff (Either RESTError String)
getMetricsHash session (_ /\ { corpusId, limit, listId, tabType }) = do
getMetricsHash session (_ /\ { corpusId, listId, tabType }) = do
get session $ ChartHash { chartType: ChartPie, listId: mListId, tabType } (Just corpusId)
where
mListId = if listId == 0 then Nothing else (Just listId)
......@@ -99,19 +99,19 @@ handleResponse :: HashedResponse ChartMetrics -> HistoMetrics
handleResponse (HashedResponse { value: ChartMetrics ms }) = ms."data"
mkRequest :: Session -> ReloadPath -> GUC.Request
mkRequest session (_ /\ path@{ corpusId, limit, listId, tabType }) = GUC.makeGetRequest session $ chartUrl path
mkRequest session (_ /\ path) = GUC.makeGetRequest session $ chartUrl path
pie :: R2.Leaf Props
pie props = R.createElement pieCpt props []
pieCpt :: R.Component Props
pieCpt = here.component "pie" cpt
where
cpt { path, session, onClick, onInit } _ = do
cpt { errors, path, session, onClick, onInit } _ = do
reload <- T.useBox T2.newReload
pure $ metricsWithCacheLoadView {
getMetricsHash
errors
, getMetricsHash
, handleResponse
, loaded: loadedPie
, mkRequest: mkRequest session
......@@ -123,7 +123,7 @@ pieCpt = here.component "pie" cpt
}
loadedPie :: Record MetricsProps -> HistoMetrics -> R.Element
loadedPie p@{ path, reload, session } loaded =
loadedPie p loaded =
H.div {} [
{- U.reloadButton reload
, U.chartUpdateButton { chartType: ChartPie, path, reload, session }
......@@ -133,15 +133,15 @@ loadedPie p@{ path, reload, session } loaded =
bar :: Record Props -> R.Element
bar props = R.createElement barCpt props []
barCpt :: R.Component Props
barCpt = here.component "bar" cpt
where
cpt {path, session, onClick, onInit} _ = do
cpt { errors, path, session, onClick, onInit} _ = do
reload <- T.useBox T2.newReload
pure $ metricsWithCacheLoadView {
getMetricsHash
errors
, getMetricsHash
, handleResponse
, loaded: loadedBar
, mkRequest: mkRequest session
......@@ -153,7 +153,7 @@ barCpt = here.component "bar" cpt
}
loadedBar :: Record MetricsProps -> Loaded -> R.Element
loadedBar p@{ path, reload, session } loaded =
loadedBar p loaded =
H.div {} [
{- U.reloadButton reload
, U.chartUpdateButton { chartType: ChartBar, path, reload, session }
......
module Gargantext.Components.Nodes.Corpus.Chart.Predefined where
import Data.Argonaut (class DecodeJson, class EncodeJson, decodeJson, encodeJson)
import Gargantext.Prelude
import Data.Generic.Rep (class Generic)
import Data.Maybe (Maybe(..), fromMaybe)
import Data.Nullable (Nullable)
import Data.Ord.Generic (genericCompare)
import Data.Show.Generic (genericShow)
import Effect (Effect)
......@@ -12,13 +12,12 @@ import Gargantext.Components.Nodes.Corpus.Chart.Histo (histo)
import Gargantext.Components.Nodes.Corpus.Chart.Metrics (metrics)
import Gargantext.Components.Nodes.Corpus.Chart.Pie (pie)
import Gargantext.Components.Nodes.Corpus.Chart.Tree (tree)
import Gargantext.Prelude
import Gargantext.Sessions (Session)
import Gargantext.Types (NodeID, Mode(..), TabSubType(..), TabType(..), modeTabType)
import Gargantext.Types (FrontendError, Mode(..), NodeID, TabSubType(..), TabType(..), modeTabType)
import Reactix as R
import Simple.JSON as JSON
import Simple.JSON.Generics as JSONG
import Toestand as T
data PredefinedChart =
CDocsHistogram
......@@ -57,44 +56,50 @@ allPredefinedCharts =
type Params =
( corpusId :: NodeID
, session :: Session
-- optinal params
, errors :: T.Box (Array FrontendError)
, limit :: Maybe Int
, listId :: Maybe Int
, onClick :: Maybe (MouseEvent -> Effect Unit)
, onInit :: Maybe (EChartsInstance -> Effect Unit)
, session :: Session
)
render :: PredefinedChart -> Record Params -> R.Element
render CDocsHistogram { corpusId, listId, session, onClick, onInit } = histo { path, session, onClick, onInit }
render CDocsHistogram { corpusId, errors, listId, session, onClick, onInit } =
histo { errors, path, session, onClick, onInit }
where
path = { corpusId
, listId: fromMaybe 0 listId
, limit: Nothing
, tabType: TabCorpus TabDocs
}
render CAuthorsPie { corpusId, listId, session, onClick, onInit } = pie { path, session, onClick, onInit }
render CAuthorsPie { corpusId, errors, listId, session, onClick, onInit } =
pie { errors, path, session, onClick, onInit }
where
path = { corpusId
, listId: fromMaybe 0 listId
, limit: Nothing
, tabType: TabCorpus (TabNgramType $ modeTabType Authors)
}
render CInstitutesTree { corpusId, limit, listId, session, onClick, onInit } = tree { path, session, onClick, onInit }
render CInstitutesTree { corpusId, errors, limit, listId, session, onClick, onInit } =
tree { errors, path, session, onClick, onInit }
where
path = { corpusId
, limit
, listId: fromMaybe 0 listId
, tabType: TabCorpus (TabNgramType $ modeTabType Institutes)
}
render CTermsMetrics { corpusId, limit, listId, session, onClick, onInit } = metrics { path, session, onClick, onInit }
render CTermsMetrics { corpusId, errors, limit, listId, session, onClick, onInit } =
metrics { errors, path, session, onClick, onInit }
where
path = { corpusId
, limit
, listId: fromMaybe 0 listId
, tabType: TabCorpus (TabNgramType $ modeTabType Terms)
}
render CSourcesBar { corpusId, limit, listId, session, onClick, onInit } = metrics { path, session, onClick, onInit }
render CSourcesBar { corpusId, errors, limit, listId, session, onClick, onInit } =
metrics { errors, path, session, onClick, onInit }
where
path = { corpusId
, limit
......
......@@ -75,15 +75,15 @@ mkRequest session (_ /\ path@{ corpusId, limit, listId, tabType }) = GUC.makeGet
tree :: Record Props -> R.Element
tree props = R.createElement treeCpt props []
treeCpt :: R.Component Props
treeCpt = here.component "tree" cpt
where
cpt {path, session, onClick, onInit} _ = do
cpt { errors, path, session, onClick, onInit } _ = do
reload <- T.useBox T2.newReload
pure $ metricsWithCacheLoadView {
getMetricsHash
errors
, getMetricsHash
, handleResponse
, loaded
, mkRequest: mkRequest session
......
......@@ -6,8 +6,9 @@ import Effect (Effect)
import Gargantext.Components.Charts.Options.Type (EChartsInstance, MouseEvent)
import Gargantext.Prelude (Unit)
import Gargantext.Sessions (Session)
import Gargantext.Types (TabType)
import Gargantext.Types (FrontendError, TabType)
import Gargantext.Utils.Toestand as T2
import Toestand as T
type Path = (
corpusId :: Int
......@@ -17,7 +18,8 @@ type Path = (
)
type Props = (
path :: Record Path
errors :: T.Box (Array FrontendError)
, path :: Record Path
, session :: Session
, onClick :: Maybe (MouseEvent -> Effect Unit)
, onInit :: Maybe (EChartsInstance -> Effect Unit)
......
......@@ -4,15 +4,9 @@ import Data.Array as A
import Data.Either (Either(..))
import Data.List as List
import Data.Maybe (Maybe(..), fromMaybe)
import DOM.Simple.Console (log, log2)
import Effect (Effect)
import Effect.Aff (launchAff_)
import Effect.Class (liftEffect)
import Reactix as R
import Reactix.DOM.HTML as H
import Toestand as T
import Gargantext.Components.Forest.Tree (doSearch)
import Gargantext.Components.Nodes.Corpus (fieldsCodeEditor)
import Gargantext.Components.Nodes.Corpus.Chart.Predefined as P
import Gargantext.Components.Nodes.Dashboard.Types as DT
......@@ -20,21 +14,28 @@ import Gargantext.Components.Nodes.Types (FTFieldList(..), FTFieldsWithIndex(..)
import Gargantext.Hooks.Loader (useLoader)
import Gargantext.Prelude (Unit, bind, discard, pure, read, show, unit, ($), (<$>), (<>), (==))
import Gargantext.Sessions (Session, sessionId)
import Gargantext.Types (NodeID)
import Gargantext.Types (FrontendError, NodeID)
import Gargantext.Utils.Reactix as R2
import Gargantext.Utils.Toestand as T2
import Reactix as R
import Reactix.DOM.HTML as H
import Record as Record
import Toestand as T
here :: R2.Here
here = R2.here "Gargantext.Components.Nodes.Corpus.Dashboard"
type Props = ( nodeId :: NodeID, session :: Session )
type Props =
( errors :: T.Box (Array FrontendError)
, nodeId :: NodeID
, session :: Session )
dashboardLayout :: R2.Component Props
dashboardLayout = R.createElement dashboardLayoutCpt
dashboardLayoutCpt :: R.Component Props
dashboardLayoutCpt = here.component "dashboardLayout" cpt where
cpt { nodeId, session } content = do
pure $ dashboardLayoutWithKey { key, nodeId, session } content
cpt props@{ nodeId, session } content = do
pure $ dashboardLayoutWithKey (Record.merge props { key }) content
where
key = show (sessionId session) <> "-" <> show nodeId
......@@ -48,7 +49,7 @@ dashboardLayoutWithKey = R.createElement dashboardLayoutWithKeyCpt
dashboardLayoutWithKeyCpt :: R.Component KeyProps
dashboardLayoutWithKeyCpt = here.component "dashboardLayoutWithKey" cpt
where
cpt { nodeId, session } _ = do
cpt { errors, nodeId, session } _ = do
reload <- T.useBox T2.newReload
reload' <- T.useLive T.unequal reload
......@@ -60,6 +61,7 @@ dashboardLayoutWithKeyCpt = here.component "dashboardLayoutWithKey" cpt
dashboardLayoutLoaded { charts
, corpusId: parentId
, defaultListId: 0
, errors
, fields
, nodeId
, onChange: onChange nodeId reload (DT.Hyperdata h)
......@@ -75,7 +77,7 @@ dashboardLayoutWithKeyCpt = here.component "dashboardLayoutWithKey" cpt
, session }
liftEffect $ do
_ <- case res of
Left err -> log2 "[dashboardLayoutWithKey] onChange RESTError" err
Left err -> here.log2 "[dashboardLayoutWithKey] onChange RESTError" err
_ -> pure unit
T2.reload reload
......@@ -83,6 +85,7 @@ type LoadedProps =
( charts :: Array P.PredefinedChart
, corpusId :: NodeID
, defaultListId :: Int
, errors :: T.Box (Array FrontendError)
, fields :: FTFieldList
, onChange :: { charts :: Array P.PredefinedChart
, fields :: FTFieldList } -> Effect Unit
......@@ -95,7 +98,7 @@ dashboardLayoutLoaded = R.createElement dashboardLayoutLoadedCpt
dashboardLayoutLoadedCpt :: R.Component LoadedProps
dashboardLayoutLoadedCpt = here.component "dashboardLayoutLoaded" cpt
where
cpt { charts, corpusId, defaultListId, fields, nodeId, onChange, session } _ = do
cpt { charts, corpusId, defaultListId, errors, fields, nodeId, onChange, session } _ = do
pure $ H.div {}
[ dashboardCodeEditor { fields
, nodeId
......@@ -119,7 +122,13 @@ dashboardLayoutLoadedCpt = here.component "dashboardLayoutLoaded" cpt
, fields }
chartsEls = A.mapWithIndex chartIdx charts
chartIdx idx chart =
renderChart { chart, corpusId, defaultListId, onChange: onChangeChart, onRemove, session } []
renderChart { chart
, corpusId
, defaultListId
, errors
, onChange: onChangeChart
, onRemove
, session } []
where
onChangeChart c = do
onChange { charts: fromMaybe charts (A.modifyAt idx (\_ -> c) charts)
......@@ -193,6 +202,7 @@ type PredefinedChartProps =
( chart :: P.PredefinedChart
, corpusId :: NodeID
, defaultListId :: Int
, errors :: T.Box (Array FrontendError)
, onChange :: P.PredefinedChart -> Effect Unit
, onRemove :: Unit -> Effect Unit
, session :: Session
......@@ -203,7 +213,7 @@ renderChart = R.createElement renderChartCpt
renderChartCpt :: R.Component PredefinedChartProps
renderChartCpt = here.component "renderChart" cpt
where
cpt { chart, corpusId, defaultListId, onChange, onRemove, session } _ = do
cpt { chart, corpusId, defaultListId, errors, onChange, onRemove, session } _ = do
pure $ H.div { className: "row chart card" }
[ H.div { className: "card-header" }
[ H.div { className: "row" }
......@@ -234,6 +244,7 @@ renderChartCpt = here.component "renderChart" cpt
value = R.unsafeEventValue e
onRemoveClick _ = onRemove unit
params = { corpusId
, errors
, limit: Just 1000
, listId: Just defaultListId
, session
......
module Gargantext.Components.Nodes.Home where
import Gargantext.Prelude
import Control.Bind ((=<<))
import Data.Maybe (Maybe(..))
import Data.Newtype (class Newtype)
import Effect (Effect)
......@@ -13,10 +16,10 @@ import Gargantext.Components.Nodes.Home.Public (renderPublic)
import Gargantext.Config as Config
import Gargantext.Ends (Backend(..))
import Gargantext.License (license)
import Gargantext.Prelude
import Gargantext.Sessions (Sessions)
import Gargantext.Sessions as Sessions
import Gargantext.Sessions.Types (Session(..))
import Gargantext.Types (FrontendError)
import Gargantext.Utils.Reactix as R2
import Gargantext.Utils.Toestand as T2
import Reactix as R
......@@ -53,7 +56,8 @@ langLandingData LL_EN = En.landingData
------------------------------------------------------------------------
type HomeProps s l =
( backend :: T.Box (Maybe Backend)
( backend :: T.Box (Maybe Backend)
, errors :: T.Box (Array FrontendError)
, lang :: LandingLang
, sessions :: s
, showLogin :: l
......@@ -68,7 +72,7 @@ homeLayoutCpt :: forall s l. T.Read s Sessions => T.ReadWrite l Boolean
=> R.Component (HomeProps s l)
homeLayoutCpt = here.component "homeLayout" cpt
where
cpt { backend, lang, sessions, showLogin, tasks, reloadForest} _ = do
cpt { backend, errors, lang, sessions, showLogin, tasks, reloadForest} _ = do
backend' <- T.useLive T.unequal backend
sessions' <- T.useLive T.unequal sessions
let landingData = langLandingData lang
......@@ -77,7 +81,7 @@ homeLayoutCpt = here.component "homeLayout" cpt
[ H.div { className: "home-title container1" }
[ jumboTitle landingData ]
, H.div { className: "home-research-form container1" } [] -- TODO
, joinButtonOrTutorial tasks reloadForest sessions' (click backend')
, joinButtonOrTutorial errors tasks reloadForest sessions' (click backend')
, H.div { className: "home-public container1" }
[ renderPublic { }
, H.div { className:"col-12 d-flex justify-content-center" }
......@@ -98,11 +102,16 @@ homeLayoutCpt = here.component "homeLayout" cpt
T.write_ true showLogin
Just _ -> T.write_ true showLogin
joinButtonOrTutorial :: forall e. T.Box GAT.Storage -> T2.ReloadS -> Sessions -> (e -> Effect Unit) -> R.Element
joinButtonOrTutorial tasks reloadForest sessions click =
joinButtonOrTutorial :: forall e. T.Box (Array FrontendError)
-> T.Box GAT.Storage
-> T2.ReloadS
-> Sessions
-> (e -> Effect Unit)
-> R.Element
joinButtonOrTutorial errors tasks reloadForest sessions click =
if Sessions.null sessions
then joinButton click
else tutorial {tasks, reloadForest, sessions: Sessions.unSessions sessions}
else tutorial { errors, tasks, reloadForest, sessions: Sessions.unSessions sessions }
joinButton :: forall e. (e -> Effect Unit) -> R.Element
joinButton click =
......@@ -148,11 +157,17 @@ summary =
, H.ol {} (map toSummary tutos) ] ]
toSummary (Tuto x) = H.li {} [ H.a {href: "#" <> x.id} [ H.text x.title ]]
tutorial :: R2.Leaf (sessions :: Array Session, tasks :: T.Box GAT.Storage, reloadForest :: T.Box T2.Reload)
type TutorialProps =
( errors :: T.Box (Array FrontendError)
, sessions :: Array Session
, tasks :: T.Box GAT.Storage
, reloadForest :: T.Box T2.Reload )
tutorial :: R2.Leaf TutorialProps
tutorial props = R.createElement tutorialCpt props []
tutorialCpt :: R.Component (sessions :: Array Session, tasks :: T.Box GAT.Storage, reloadForest :: T.Box T2.Reload)
tutorialCpt :: R.Component TutorialProps
tutorialCpt = here.component "tutorial" cpt where
cpt {sessions, tasks, reloadForest} _ = do
cpt { errors, sessions, tasks, reloadForest } _ = do
let folders = makeFolders sessions
pure $ H.div { className: "mx-auto container" }
......@@ -178,7 +193,7 @@ tutorialCpt = here.component "tutorial" cpt where
sessionToFolder session@(Session {treeId, username, backend: (Backend {name})}) =
H.span { className: "folder" } [
H.div { className: "d-flex justify-content-center" } [ H.text (username <> "@" <> name) ]
, H.div {} [ FV.folderView {session, tasks, reloadForest, nodeId: treeId, backFolder: false} ] ]
, H.div {} [ FV.folderView { errors, session, tasks, reloadForest, nodeId: treeId, backFolder: false} ] ]
startTutos :: Array Tuto
startTutos =
......
module Gargantext.Components.Nodes.Lists where
import Gargantext.Prelude
import Data.Maybe (Maybe)
import Effect (Effect)
import Effect.Aff (launchAff_)
import Reactix as R
import Reactix.DOM.HTML as H
import Record as Record
import Toestand as T
import Gargantext.AsyncTasks as GAT
import Gargantext.Components.NgramsTable.Loader (clearCache)
import Gargantext.Components.Node (NodePoly(..))
......@@ -17,18 +14,23 @@ import Gargantext.Components.Nodes.Lists.Tabs as Tabs
import Gargantext.Components.Nodes.Lists.Types (CacheState(..), SidePanel)
import Gargantext.Components.Table as Table
import Gargantext.Hooks.Loader (useLoader)
import Gargantext.Prelude
import Gargantext.Sessions (WithSession, WithSessionContext, Session, sessionId, getCacheState, setCacheState)
import Gargantext.Types (FrontendError)
import Gargantext.Types as GT
import Gargantext.Utils.Reactix as R2
import Gargantext.Utils.Toestand as T2
import Reactix as R
import Reactix.DOM.HTML as H
import Record as Record
import Toestand as T
here :: R2.Here
here = R2.here "Gargantext.Components.Nodes.Lists"
--------------------------------------------------------
type CommonPropsNoSession =
( nodeId :: Int
( errors :: T.Box (Array FrontendError)
, nodeId :: Int
, reloadForest :: T2.ReloadS
, reloadMainPage :: T2.ReloadS
, reloadRoot :: T2.ReloadS
......@@ -59,7 +61,8 @@ listsLayoutWithKey :: R2.Component KeyProps
listsLayoutWithKey = R.createElement listsLayoutWithKeyCpt
listsLayoutWithKeyCpt :: R.Component KeyProps
listsLayoutWithKeyCpt = here.component "listsLayoutWithKey" cpt where
cpt { nodeId
cpt { errors
, nodeId
, reloadForest
, reloadMainPage
, reloadRoot
......@@ -98,6 +101,7 @@ listsLayoutWithKeyCpt = here.component "listsLayoutWithKey" cpt where
, cacheState
, corpusData
, corpusId
, errors
, key: "listsLayoutWithKey-tabs-" <> (show cacheState')
, reloadForest
, reloadRoot
......
module Gargantext.Components.Nodes.Lists.Tabs where
import Gargantext.Components.Nodes.Lists.Types
import Data.Array as A
import Data.Maybe (Maybe(..), fromMaybe)
import Data.Tuple (fst)
import Data.Tuple.Nested ((/\))
import Effect.Class (liftEffect)
import Gargantext.AsyncTasks as GAT
......@@ -15,11 +12,11 @@ import Gargantext.Components.Nodes.Corpus.Chart.Pie (pie, bar)
import Gargantext.Components.Nodes.Corpus.Chart.Tree (tree)
import Gargantext.Components.Nodes.Corpus.Chart.Utils (mNgramsTypeFromTabType)
import Gargantext.Components.Nodes.Corpus.Types (CorpusData)
import Gargantext.Components.Search as S
import Gargantext.Components.Nodes.Lists.Types
import Gargantext.Components.Tab as Tab
import Gargantext.Prelude (bind, pure, unit, ($), (<>))
import Gargantext.Sessions (Session)
import Gargantext.Types (ChartType(..), CTabNgramType(..), Mode(..), TabSubType(..), TabType(..), modeTabType)
import Gargantext.Types (CTabNgramType(..), FrontendError, Mode(..), TabSubType(..), TabType(..), modeTabType)
import Gargantext.Utils.Reactix as R2
import Gargantext.Utils.Toestand as T2
import Reactix as R
......@@ -36,6 +33,7 @@ type Props = (
, cacheState :: T.Box CacheState
, corpusData :: CorpusData
, corpusId :: Int
, errors :: T.Box (Array FrontendError)
, reloadForest :: T2.ReloadS
, reloadRoot :: T2.ReloadS
, session :: Session
......@@ -64,12 +62,12 @@ type NgramsViewProps = ( mode :: Mode | Props )
ngramsView :: R2.Component NgramsViewProps
ngramsView = R.createElement ngramsViewCpt
ngramsViewCpt :: R.Component NgramsViewProps
ngramsViewCpt = here.component "ngramsView" cpt where
cpt props@{ cacheState
, corpusData: { defaultListId }
, corpusId
, errors
, reloadForest
, reloadRoot
, mode
......@@ -161,7 +159,7 @@ ngramsViewCpt = here.component "ngramsView" cpt where
]
charts params _ = [ chart params mode ]
chart path Authors = pie { path, session, onClick: Nothing, onInit: Nothing }
chart path Institutes = tree { path, session, onClick: Nothing, onInit: Nothing }
chart path Sources = bar { path, session, onClick: Nothing, onInit: Nothing }
chart path Terms = metrics { path, session, onClick: Nothing, onInit: Nothing }
chart path Authors = pie { errors, path, session, onClick: Nothing, onInit: Nothing }
chart path Institutes = tree { errors, path, session, onClick: Nothing, onInit: Nothing }
chart path Sources = bar { errors, path, session, onClick: Nothing, onInit: Nothing }
chart path Terms = metrics { errors, path, session, onClick: Nothing, onInit: Nothing }
......@@ -7,10 +7,6 @@ import Data.Maybe (Maybe(..))
import Data.Show.Generic (genericShow)
import Data.Tuple.Nested ((/\))
import Effect.Aff (launchAff_)
import Reactix as R
import Reactix.DOM.HTML as H
import Toestand as T
import Gargantext.Components.Charts.Options.ECharts (dispatchAction)
import Gargantext.Components.Charts.Options.Type (EChartsInstance, EChartActionData)
import Gargantext.Components.DocsTable as DT
......@@ -28,8 +24,11 @@ import Gargantext.Components.Table as Table
import Gargantext.Ends (Frontends)
import Gargantext.Hooks.Loader (useLoader)
import Gargantext.Sessions (WithSession, Session, getCacheState)
import Gargantext.Types (CTabNgramType(..), ListId, NodeID, SidePanelState(..), TabSubType(..), TabType(..))
import Gargantext.Types (CTabNgramType(..), FrontendError, ListId, NodeID, SidePanelState(..), TabSubType(..), TabType(..))
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.Nodes.Texts"
......@@ -37,8 +36,9 @@ here = R2.here "Gargantext.Components.Nodes.Texts"
--------------------------------------------------------
type CommonPropsNoSession = (
frontends :: Frontends
type CommonPropsNoSession =
( errors :: T.Box (Array FrontendError)
, frontends :: Frontends
, nodeId :: NodeID
, sidePanel :: T.Box (Maybe (Record TT.SidePanel))
, sidePanelState :: T.Box SidePanelState
......@@ -49,12 +49,12 @@ type Props = WithSession CommonPropsNoSession
textsLayout :: R2.Component Props
textsLayout = R.createElement textsLayoutCpt
textsLayoutCpt :: R.Component Props
textsLayoutCpt = here.component "textsLayout" cpt where
cpt { frontends, nodeId, session, sidePanel, sidePanelState } children = do
pure $ textsLayoutWithKey { frontends
, key
cpt { errors, frontends, nodeId, session, sidePanel, sidePanelState } children = do
pure $ textsLayoutWithKey { key
, errors
, frontends
, nodeId
, session
, sidePanel
......@@ -67,6 +67,7 @@ textsLayoutCpt = here.component "textsLayout" cpt where
type KeyProps = (
key :: String
, errors :: T.Box (Array FrontendError)
, frontends :: Frontends
, nodeId :: NodeID
, session :: Session
......@@ -79,7 +80,12 @@ textsLayoutWithKey = R.createElement textsLayoutWithKeyCpt
textsLayoutWithKeyCpt :: R.Component KeyProps
textsLayoutWithKeyCpt = here.component "textsLayoutWithKey" cpt
where
cpt { frontends, nodeId, session, sidePanel, sidePanelState } _children = do
cpt { errors
, frontends
, nodeId
, session
, sidePanel
, sidePanelState } _children = do
cacheState <- T.useBox $ getCacheState LT.CacheOff session nodeId
cacheState' <- T.useLive T.unequal cacheState
......@@ -109,6 +115,7 @@ textsLayoutWithKeyCpt = here.component "textsLayoutWithKey" cpt
, tabs { cacheState
, corpusData
, corpusId
, errors
, frontends
, session
, sidePanel
......@@ -143,6 +150,7 @@ type TabsProps =
, corpusData :: CorpusData
, corpusId :: NodeID
, eChartsInstance :: T.Box (Maybe EChartsInstance)
, errors :: T.Box (Array FrontendError)
, frontends :: Frontends
, session :: Session
, sidePanel :: T.Box (Maybe (Record TT.SidePanel))
......@@ -159,6 +167,7 @@ tabsCpt = here.component "tabs" cpt
, corpusId
, corpusData
, eChartsInstance
, errors
, frontends
, session
, sidePanel
......@@ -197,7 +206,7 @@ tabsCpt = here.component "tabs" cpt
activeTab
, tabs: [
"Documents" /\ R.fragment [
histo { path, session, onClick, onInit }
histo { errors, path, session, onClick, onInit }
, docView' path TabDocs
]
, "Trash" /\ docView' path TabTrash
......@@ -214,6 +223,7 @@ tabsCpt = here.component "tabs" cpt
docView' path tabType = docView { cacheState
, corpusData
, corpusId
, errors
, frontends
, listId: path.listId
-- , path
......@@ -228,6 +238,7 @@ type DocViewProps a = (
cacheState :: T.Box LT.CacheState
, corpusData :: CorpusData
, corpusId :: NodeID
, errors :: T.Box (Array FrontendError)
, frontends :: Frontends
, listId :: ListId
-- , path :: Record DT.Path
......@@ -240,7 +251,6 @@ type DocViewProps a = (
docView :: forall a. R2.Component (DocViewProps a)
docView = R.createElement docViewCpt
docViewCpt :: forall a. R.Component (DocViewProps a)
docViewCpt = here.component "docView" cpt
where
......@@ -250,6 +260,7 @@ docViewCpt = here.component "docView" cpt
-- docViewLayoutRec :: forall a. DocViewProps a -> Record DT.LayoutProps
docViewLayoutRec { cacheState
, corpusId
, errors
, frontends
, listId
, session
......@@ -260,6 +271,7 @@ docViewLayoutRec { cacheState
} =
{ cacheState
, chart : H.div {} []
, errors
, frontends
, listId
, mCorpusId: Just corpusId
......@@ -275,6 +287,7 @@ docViewLayoutRec { cacheState
}
docViewLayoutRec { cacheState
, corpusId
, errors
, frontends
, listId
, session
......@@ -285,6 +298,7 @@ docViewLayoutRec { cacheState
} =
{ cacheState
, chart : H.div {} []
, errors
, frontends
, listId
, mCorpusId: Just corpusId
......@@ -300,6 +314,7 @@ docViewLayoutRec { cacheState
}
docViewLayoutRec { cacheState
, corpusId
, errors
, frontends
, listId
, session
......@@ -310,6 +325,7 @@ docViewLayoutRec { cacheState
} =
{ cacheState
, chart : H.div {} []
, errors
, frontends
, listId
, mCorpusId: Just corpusId
......@@ -325,6 +341,7 @@ docViewLayoutRec { cacheState
}
docViewLayoutRec { cacheState
, corpusId
, errors
, frontends
, listId
, session
......@@ -335,6 +352,7 @@ docViewLayoutRec { cacheState
} =
{ cacheState
, chart : H.div {} []
, errors
, frontends
, listId
, mCorpusId: Just corpusId
......@@ -351,6 +369,7 @@ docViewLayoutRec { cacheState
-- DUMMY
docViewLayoutRec { cacheState
, corpusId
, errors
, frontends
, listId
, session
......@@ -361,6 +380,7 @@ docViewLayoutRec { cacheState
} =
{ cacheState
, chart : H.div {} []
, errors
, frontends
, listId
, mCorpusId: Just corpusId
......
......@@ -5,12 +5,6 @@ import Gargantext.Prelude
import Data.Array as A
import Data.Maybe (Maybe(..))
import Data.Tuple.Nested ((/\))
import Reactix as R
import Reactix.DOM.HTML as H
import Record as Record
import Record.Extra as RE
import Toestand as T
import Gargantext.Components.App.Data (Boxes)
import Gargantext.Components.ErrorsView (errorsView)
import Gargantext.Components.Footer (footer)
......@@ -43,6 +37,11 @@ import Gargantext.Sessions (Session, WithSession)
import Gargantext.Sessions as Sessions
import Gargantext.Types (CorpusId, Handed(..), ListId, NodeID, NodeType(..), SessionId, SidePanelState(..), reverseHanded)
import Gargantext.Utils.Reactix as R2
import Reactix as R
import Reactix.DOM.HTML as H
import Record as Record
import Record.Extra as RE
import Toestand as T
here :: R2.Here
here = R2.here "Gargantext.Components.Router"
......@@ -114,6 +113,7 @@ forest p = R.createElement forestCpt p []
forestCpt :: R.Component Props
forestCpt = here.component "forest" cpt where
cpt { boxes: { backend
, errors
, forestOpen
, handed
, reloadForest
......@@ -133,6 +133,7 @@ forestCpt = here.component "forest" cpt where
then mempty
else Forest.forestLayout
{ backend
, errors
, forestOpen
, frontends: defaultFrontends
, handed
......@@ -284,7 +285,11 @@ corpusCpt = here.component "corpus" cpt where
cpt props@{ boxes, nodeId } _ = do
let sessionProps = RE.pick props :: Record SessionProps
pure $ authed (Record.merge { content: \session ->
corpusLayout { nodeId, session, tasks: boxes.tasks, reloadForest: boxes.reloadForest } } sessionProps) []
corpusLayout { errors: boxes.errors
, nodeId
, session
, tasks: boxes.tasks
, reloadForest: boxes.reloadForest } } sessionProps) []
type CorpusDocumentProps =
( corpusId :: CorpusId
......@@ -310,10 +315,10 @@ dashboard = R.createElement dashboardCpt
dashboardCpt :: R.Component SessionNodeProps
dashboardCpt = here.component "dashboard" cpt
where
cpt props@{ nodeId } _ = do
cpt props@{ boxes: { errors }, nodeId } _ = do
let sessionProps = RE.pick props :: Record SessionProps
pure $ authed (Record.merge { content: \session ->
dashboardLayout { nodeId, session } [] } sessionProps) []
dashboardLayout { errors, nodeId, session } [] } sessionProps) []
type DocumentProps = ( listId :: ListId | SessionNodeProps )
......@@ -356,14 +361,15 @@ home :: R2.Component Props
home = R.createElement homeCpt
homeCpt :: R.Component Props
homeCpt = here.component "home" cpt where
cpt { boxes: { backend, sessions, showLogin, tasks, reloadForest} } _ = do
pure $ homeLayout { backend, lang: LL_EN, sessions, showLogin, tasks, reloadForest }
cpt { boxes: { backend, errors, sessions, showLogin, tasks, reloadForest} } _ = do
pure $ homeLayout { backend, errors, lang: LL_EN, sessions, showLogin, tasks, reloadForest }
lists :: R2.Component SessionNodeProps
lists = R.createElement listsCpt
listsCpt :: R.Component SessionNodeProps
listsCpt = here.component "lists" cpt where
cpt props@{ boxes: { reloadForest
cpt props@{ boxes: { errors
, reloadForest
, reloadMainPage
, reloadRoot
, sidePanelState
......@@ -372,7 +378,8 @@ listsCpt = here.component "lists" cpt where
, nodeId } _ = do
let sessionProps = RE.pick props :: Record SessionProps
pure $ authed (Record.merge { content: \session ->
Lists.listsLayout { nodeId
Lists.listsLayout { errors
, nodeId
, reloadForest
, reloadMainPage
, reloadRoot
......@@ -420,22 +427,25 @@ teamCpt = here.component "team" cpt where
cpt props@{ boxes, nodeId } _ = do
let sessionProps = RE.pick props :: Record SessionProps
pure $ authed (Record.merge { content: \session ->
corpusLayout { nodeId
corpusLayout { errors: boxes.errors
, nodeId
, reloadForest: boxes.reloadForest
, session
, tasks: boxes.tasks
, reloadForest: boxes.reloadForest } } sessionProps) []
, tasks: boxes.tasks } } sessionProps) []
texts :: R2.Component SessionNodeProps
texts = R.createElement textsCpt
textsCpt :: R.Component SessionNodeProps
textsCpt = here.component "texts" cpt
where
cpt props@{ boxes: { sidePanelState
cpt props@{ boxes: { errors
, sidePanelState
, sidePanelTexts }
, nodeId } _ = do
let sessionProps = RE.pick props :: Record SessionProps
pure $ authed (Record.merge { content: \session ->
Texts.textsLayout { frontends: defaultFrontends
Texts.textsLayout { errors
, frontends: defaultFrontends
, nodeId
, session
, sidePanel: sidePanelTexts
......@@ -445,7 +455,8 @@ user :: R2.Component SessionNodeProps
user = R.createElement userCpt
userCpt :: R.Component SessionNodeProps
userCpt = here.component "user" cpt where
cpt props@{ boxes: { reloadForest
cpt props@{ boxes: { errors
, reloadForest
, reloadRoot
, sidePanelState
, sidePanelTexts
......@@ -453,7 +464,8 @@ userCpt = here.component "user" cpt where
, nodeId } _ = do
let sessionProps = RE.pick props :: Record SessionProps
pure $ authed (Record.merge { content: \session ->
userLayout { frontends: defaultFrontends
userLayout { errors
, frontends: defaultFrontends
, nodeId
, reloadForest
, reloadRoot
......@@ -469,7 +481,8 @@ contact = R.createElement contactCpt
contactCpt :: R.Component ContactProps
contactCpt = here.component "contact" cpt where
cpt props@{ annuaireId
, boxes: { reloadForest
, boxes: { errors
, reloadForest
, reloadRoot
, sidePanelTexts
, sidePanelState
......@@ -479,6 +492,7 @@ contactCpt = here.component "contact" cpt where
-- let forestedProps = RE.pick props :: Record Props
pure $ authed (Record.merge { content: \session ->
contactLayout { annuaireId
, errors
, frontends: defaultFrontends
, nodeId
, reloadForest
......
......@@ -2,12 +2,11 @@ module Gargantext.Config.REST where
import Gargantext.Prelude
import Affjax (defaultRequest, request)
import Affjax (Error(..), defaultRequest, request)
import Affjax as Affjax
import Affjax.RequestBody (formData, formURLEncoded, string)
import Affjax.RequestHeader as ARH
import Affjax.ResponseFormat as ResponseFormat
import DOM.Simple.Console (log2)
import Data.Argonaut.Core as AC
import Data.Either (Either(..))
import Data.Foldable (foldMap)
......@@ -20,11 +19,10 @@ import Data.Tuple (Tuple)
import Effect.Aff (Aff)
import Effect.Class (liftEffect)
import Foreign as Foreign
import Gargantext.Utils.Reactix as R2
import Simple.JSON as JSON
import Web.XHR.FormData as XHRFormData
import Gargantext.Utils.Reactix as R2
type Token = String
data RESTError =
......@@ -32,10 +30,20 @@ data RESTError =
| ReadJSONError Foreign.MultipleErrors
derive instance Generic RESTError _
instance Show RESTError where
show (SendResponseError e) = "SendResponseError " <> showError e
where
showError (RequestContentError e') = "(RequestContentError " <> show e' <> ")"
showError (ResponseBodyError fe rf) = "(ResponseBodyError " <> show fe <> " (rf)" -- <> show rf <> ")"
showError (TimeoutError) = "(TimeoutError)"
showError (RequestFailedError) = "(RequestFailedError)"
showError (XHROtherError e') = "(XHROtherError " <> show e' <> ")"
show (ReadJSONError e) = "ReadJSONError " <> show e
instance Eq RESTError where
-- this is crude but we need it only because of useLoader
eq _ _ = false
readJSON :: forall a b. JSON.ReadForeign a =>
Either Affjax.Error
{ body :: AC.Json
......
module Gargantext.Config.Utils where
import Gargantext.Prelude
import Data.Array as A
import Data.Either (Either(..))
import Effect.Aff (Aff)
import Effect.Class (liftEffect)
import Gargantext.Config.REST (RESTError)
import Gargantext.Types (FrontendError(..))
import Gargantext.Utils.Reactix as R2
import Toestand as T
here :: R2.Here
here = R2.here "Gargantext.Config.Utils"
handleRESTError :: forall a. T.Box (Array FrontendError)
-> Either RESTError a
-> (a -> Aff Unit)
-> Aff Unit
handleRESTError errors (Left error) _ = liftEffect $ do
T.modify_ (A.cons $ FRESTError { error }) errors
here.log2 "[handleTaskError] RESTError" error
handleRESTError _ (Right task) handler = handler task
......@@ -2,6 +2,7 @@ module Gargantext.Hooks.Loader where
import Gargantext.Prelude
import Data.Array as A
import Data.Either (Either(..))
import Data.Generic.Rep (class Generic)
import Data.Maybe (Maybe(..), isJust, maybe)
......@@ -10,15 +11,16 @@ import Effect (Effect)
import Effect.Aff (Aff, launchAff_, throwError)
import Effect.Class (liftEffect)
import Effect.Exception (error)
import Reactix as R
import Simple.JSON as JSON
import Toestand as T
import Gargantext.Components.LoadingSpinner (loadingSpinner)
import Gargantext.Config.REST (RESTError)
import Gargantext.Config.Utils (handleRESTError)
import Gargantext.Types (FrontendError(..))
import Gargantext.Utils.CacheAPI as GUC
import Gargantext.Utils.Crypto (Hash)
import Gargantext.Utils.Reactix as R2
import Reactix as R
import Simple.JSON as JSON
import Toestand as T
here :: R2.Here
here = R2.here "Gargantext.Hooks.Loader"
......@@ -96,22 +98,24 @@ derive newtype instance JSON.ReadForeign a => JSON.ReadForeign (HashedResponse a
derive newtype instance JSON.WriteForeign a => JSON.WriteForeign (HashedResponse a)
type LoaderWithCacheAPIProps path res ret = (
cacheEndpoint :: path -> Aff (Either RESTError Hash)
cacheEndpoint :: path -> Aff (Either RESTError Hash)
, errors :: T.Box (Array FrontendError)
, handleResponse :: HashedResponse res -> ret
, mkRequest :: path -> GUC.Request
, path :: path
, renderer :: ret -> R.Element
, mkRequest :: path -> GUC.Request
, path :: path
, renderer :: ret -> R.Element
)
useLoaderWithCacheAPI :: forall path res ret.
Eq ret => Eq path => JSON.ReadForeign res =>
Record (LoaderWithCacheAPIProps path res ret)
-> R.Hooks R.Element
useLoaderWithCacheAPI { cacheEndpoint, handleResponse, mkRequest, path, renderer } = do
useLoaderWithCacheAPI { cacheEndpoint, errors, handleResponse, mkRequest, path, renderer } = do
state <- T.useBox Nothing
state' <- T.useLive T.unequal state
useCachedAPILoaderEffect { cacheEndpoint
, errors
, handleResponse
, mkRequest
, path
......@@ -120,6 +124,7 @@ useLoaderWithCacheAPI { cacheEndpoint, handleResponse, mkRequest, path, renderer
type LoaderWithCacheAPIEffectProps path res ret = (
cacheEndpoint :: path -> Aff (Either RESTError Hash)
, errors :: T.Box (Array FrontendError)
, handleResponse :: HashedResponse res -> ret
, mkRequest :: path -> GUC.Request
, path :: path
......@@ -131,6 +136,7 @@ useCachedAPILoaderEffect :: forall path res ret.
Record (LoaderWithCacheAPIEffectProps path res ret)
-> R.Hooks Unit
useCachedAPILoaderEffect { cacheEndpoint
, errors
, handleResponse
, mkRequest
, path
......@@ -150,18 +156,18 @@ useCachedAPILoaderEffect { cacheEndpoint
cache <- GUC.openCache $ GUC.CacheName cacheName
-- TODO Parallelize?
hr@(HashedResponse { hash }) <- GUC.cachedJson cache req
cacheReal <- cacheEndpoint path
case cacheReal of
Left _err -> throwError $ error $ "[useCachedAPILoaderEffect] RESTError"
Right cacheReal' -> do
val <- if hash == cacheReal' then
pure hr
eCacheReal <- cacheEndpoint path
handleRESTError errors eCacheReal $ \cacheReal -> do
val <- if hash == cacheReal then
pure hr
else do
_ <- GUC.deleteReq cache req
hr'@(HashedResponse { hash: h }) <- GUC.cachedJson cache req
if h == cacheReal then
pure hr'
else do
_ <- GUC.deleteReq cache req
hr'@(HashedResponse { hash: h }) <- GUC.cachedJson cache req
if h == cacheReal' then
pure hr'
else
throwError $ error $ "[Hooks.Loader] Fetched clean cache but hashes don't match: " <> h <> " != " <> cacheReal'
liftEffect $ do
T.write_ (Just $ handleResponse val) state
let err = "[Hooks.Loader] Fetched clean cache but hashes don't match: " <> h <> " != " <> cacheReal
liftEffect $ T.modify_ (A.cons $ FStringError { error: err }) errors
throwError $ error err
liftEffect $ do
T.write_ (Just $ handleResponse val) state
......@@ -677,7 +677,7 @@ asyncTaskTypePath AddNode = "async/nobody/"
asyncTaskTypePath Form = "add/form/async/"
asyncTaskTypePath GraphRecompute = "async/recompute/"
asyncTaskTypePath ListUpload = "add/form/async/"
asyncTaskTypePath ListCSVUpload = "csv/add/form/async/"
asyncTaskTypePath ListCSVUpload = "add/form/async/"
asyncTaskTypePath Query = "query/"
asyncTaskTypePath UpdateNgramsCharts = "ngrams/async/charts/update/"
asyncTaskTypePath UpdateNode = "update/"
......@@ -779,9 +779,10 @@ toggleSidePanelState Opened = Closed
---------------------------------------------------------------------------
newtype FrontendError = FrontendError
data FrontendError = FStringError
{ error :: String
}
} | FRESTError
{ error :: RESTError }
derive instance Generic FrontendError _
instance Eq FrontendError where eq = genericEq
......@@ -86,7 +86,7 @@ cached cache req = do
mResFresh <- match cache req
case mResFresh of
Just res -> pure res
Nothing -> throwError $ error $ "Cannot add to cache"
Nothing -> throwError $ error $ "[cached] Cannot add to cache"
cachedJson :: forall a. JSON.ReadForeign a => Cache -> Request -> Aff a
cachedJson cache req = do
......
module Gargantext.Utils.Either where
import Gargantext.Prelude
import Data.Array (cons, uncons)
import Data.Either (Either(..))
import Data.Map as Map
import Data.Maybe (Maybe(..))
import Data.Tuple (Tuple(..))
eitherList :: forall l r. Array (Either l r) -> Either l (Array r)
eitherList xs = case uncons xs of
Nothing -> Right []
Just { head: Left x } -> Left x
Just { head: Right x, tail } ->
case eitherList tail of
Left err -> Left err
Right ds -> Right (cons x ds)
eitherMap :: forall k l r. Ord k => Map.Map k (Either l r) -> Either l (Map.Map k r)
eitherMap m = case eitherList (helper <$> Map.toUnfoldable m) of
Left err -> Left err
Right lst -> Right $ Map.fromFoldable lst
where
helper (Tuple _ (Left err)) = Left err
helper (Tuple k (Right v)) = Right (Tuple k v)
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