Commit 52ac326e authored by Alexandre Delanoë's avatar Alexandre Delanoë

Merge branch '318-dev-corpus-fields-editeable' of...

Merge branch '318-dev-corpus-fields-editeable' of ssh://gitlab.iscpif.fr:20022/gargantext/purescript-gargantext into dev-merge
parents a7b8a5a0 00901a4b
...@@ -12,6 +12,7 @@ import Effect.Class (liftEffect) ...@@ -12,6 +12,7 @@ import Effect.Class (liftEffect)
import Foreign (unsafeToForeign, ForeignError) import Foreign (unsafeToForeign, ForeignError)
import Gargantext.Components.GraphQL.Node (Node) import Gargantext.Components.GraphQL.Node (Node)
import Gargantext.Components.GraphQL.User (User, UserInfo, UserInfoM) import Gargantext.Components.GraphQL.User (User, UserInfo, UserInfoM)
import Gargantext.Ends (Backend(..))
import Gargantext.Sessions (Session(..)) import Gargantext.Sessions (Session(..))
import Gargantext.Utils.Reactix as R2 import Gargantext.Utils.Reactix as R2
import GraphQL.Client.Args (type (==>)) import GraphQL.Client.Args (type (==>))
...@@ -45,7 +46,7 @@ toJsonError :: NonEmptyList ForeignError -> JsonDecodeError ...@@ -45,7 +46,7 @@ toJsonError :: NonEmptyList ForeignError -> JsonDecodeError
toJsonError = unsafeCoerce -- map ForeignErrors to JsonDecodeError as you wish toJsonError = unsafeCoerce -- map ForeignErrors to JsonDecodeError as you wish
getClient :: Session -> Effect (Client UrqlClient Schema Mutation Void) getClient :: Session -> Effect (Client UrqlClient Schema Mutation Void)
getClient (Session { token }) = createClient { headers, url: "http://localhost:8008/gql" } getClient (Session { token, backend: Backend b }) = createClient { headers, url: b.baseUrl <> "/gql" }
where where
headers = [ ARH.RequestHeader "Authorization" $ "Bearer " <> token ] headers = [ ARH.RequestHeader "Authorization" $ "Bearer " <> token ]
......
...@@ -56,3 +56,23 @@ getCorpusInfo (FTFieldList as) = case List.head (List.filter isJSON as) of ...@@ -56,3 +56,23 @@ getCorpusInfo (FTFieldList as) = case List.head (List.filter isJSON as) of
, authors:"" , authors:""
, totalRecords: 0 , totalRecords: 0
} }
saveCorpusInfo :: CorpusInfo -> FTFieldList -> FTFieldList
saveCorpusInfo (CorpusInfo i) (FTFieldList fields) =
FTFieldList $ List.snoc (List.filter (not isJSON) fields) (Field {name: oName, typ: JSON { authors: i.authors
, desc: i.desc
, query: i.query
, title: i.title
, tag: oTag
}})
where
oName = case o of
Just (Field {name}) -> name
_ -> ""
oTag = case o of
Just (Field {typ: JSON {tag}}) -> tag
_ -> ""
o = List.head (List.filter isJSON fields)
...@@ -8,7 +8,6 @@ import Gargantext.Components.App.Data (Boxes) ...@@ -8,7 +8,6 @@ import Gargantext.Components.App.Data (Boxes)
import Gargantext.Components.NgramsTable.Loader (clearCache) import Gargantext.Components.NgramsTable.Loader (clearCache)
import Gargantext.Components.Node (NodePoly(..)) import Gargantext.Components.Node (NodePoly(..))
import Gargantext.Components.Nodes.Corpus (loadCorpusWithChild) import Gargantext.Components.Nodes.Corpus (loadCorpusWithChild)
import Gargantext.Components.Nodes.Corpus.Types (getCorpusInfo, CorpusInfo(..), Hyperdata(..))
import Gargantext.Components.Nodes.Lists.Tabs as Tabs import Gargantext.Components.Nodes.Lists.Tabs as Tabs
import Gargantext.Components.Nodes.Lists.Types (CacheState(..)) import Gargantext.Components.Nodes.Lists.Types (CacheState(..))
import Gargantext.Components.Table as Table import Gargantext.Components.Table as Table
...@@ -73,18 +72,18 @@ listsLayoutWithKeyCpt = here.component "listsLayoutWithKey" cpt where ...@@ -73,18 +72,18 @@ listsLayoutWithKeyCpt = here.component "listsLayoutWithKey" cpt where
, path , path
, loader: loadCorpusWithChild , loader: loadCorpusWithChild
, render: \corpusData@{ corpusId, corpusNode: NodePoly poly } -> , render: \corpusData@{ corpusId, corpusNode: NodePoly poly } ->
let { date, hyperdata : Hyperdata h, name } = poly let { name, date, hyperdata } = poly
CorpusInfo { authors, desc, query } = getCorpusInfo h.fields
in in
R.fragment [ R.fragment [
Table.tableHeaderLayout { Table.tableHeaderWithRenameLayout {
cacheState cacheState
, name
, date , date
, desc , hyperdata
, nodeId: corpusId
, session
, key: "listsLayoutWithKey-header-" <> (show cacheState') , key: "listsLayoutWithKey-header-" <> (show cacheState')
, query } []
, title: "Corpus " <> name
, user: authors } []
, Tabs.tabs { , Tabs.tabs {
activeTab activeTab
, boxes , boxes
......
...@@ -17,7 +17,7 @@ import Gargantext.Components.Node (NodePoly(..)) ...@@ -17,7 +17,7 @@ import Gargantext.Components.Node (NodePoly(..))
import Gargantext.Components.Nodes.Corpus (loadCorpusWithChild) import Gargantext.Components.Nodes.Corpus (loadCorpusWithChild)
import Gargantext.Components.Nodes.Corpus.Chart.Histo (histo) import Gargantext.Components.Nodes.Corpus.Chart.Histo (histo)
import Gargantext.Components.Nodes.Corpus.Document as D import Gargantext.Components.Nodes.Corpus.Document as D
import Gargantext.Components.Nodes.Corpus.Types (CorpusData, CorpusInfo(..), Hyperdata(..), getCorpusInfo) import Gargantext.Components.Nodes.Corpus.Types (CorpusData)
import Gargantext.Components.Nodes.Lists.Types as LT import Gargantext.Components.Nodes.Lists.Types as LT
import Gargantext.Components.Nodes.Texts.Types as TT import Gargantext.Components.Nodes.Texts.Types as TT
import Gargantext.Components.Reload (textsReloadContext) import Gargantext.Components.Reload (textsReloadContext)
...@@ -105,18 +105,17 @@ textsLayoutWithKeyCpt = here.component "textsLayoutWithKey" cpt ...@@ -105,18 +105,17 @@ textsLayoutWithKeyCpt = here.component "textsLayoutWithKey" cpt
, loader: loadCorpusWithChild , loader: loadCorpusWithChild
, path: { nodeId, session } , path: { nodeId, session }
, render: \corpusData@{ corpusId, corpusNode } -> do , render: \corpusData@{ corpusId, corpusNode } -> do
let NodePoly { date, hyperdata: Hyperdata h, name } = corpusNode let NodePoly { name, date, hyperdata } = corpusNode
CorpusInfo { authors, desc, query } = getCorpusInfo h.fields
title = "Corpus " <> name
R.fragment R.fragment
[ Table.tableHeaderLayout { cacheState [ Table.tableHeaderWithRenameLayout {
, date cacheState
, desc , name
, query , date
, title , hyperdata
, user: authors , nodeId: corpusId
, key: "textsLayoutWithKey-" <> (show cacheState') } [] , session
, key: "textsLayoutWithKey-" <> (show cacheState') } []
, tabs { boxes , tabs { boxes
, cacheState , cacheState
, corpusData , corpusData
......
module Gargantext.Components.Renameable where module Gargantext.Components.Renameable where
import Effect (Effect)
import Reactix as R
import Reactix.DOM.HTML as H
import Toestand as T
import Gargantext.Prelude import Gargantext.Prelude
import Effect (Effect)
import Gargantext.Components.InputWithEnter (inputWithEnter) import Gargantext.Components.InputWithEnter (inputWithEnter)
import Gargantext.Utils.Reactix as R2 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
...@@ -18,6 +17,7 @@ type RenameableProps = ...@@ -18,6 +17,7 @@ type RenameableProps =
( (
onRename :: String -> Effect Unit onRename :: String -> Effect Unit
, text :: String , text :: String
, icon :: String
) )
renameable :: R2.Component RenameableProps renameable :: R2.Component RenameableProps
...@@ -25,7 +25,7 @@ renameable = R.createElement renameableCpt ...@@ -25,7 +25,7 @@ renameable = R.createElement renameableCpt
renameableCpt :: R.Component RenameableProps renameableCpt :: R.Component RenameableProps
renameableCpt = here.component "renameableCpt" cpt renameableCpt = here.component "renameableCpt" cpt
where where
cpt { onRename, text } _ = do cpt { onRename, text, icon } _ = do
isEditing <- T.useBox false isEditing <- T.useBox false
state <- T.useBox text state <- T.useBox text
textRef <- R.useRef text textRef <- R.useRef text
...@@ -39,7 +39,7 @@ renameableCpt = here.component "renameableCpt" cpt ...@@ -39,7 +39,7 @@ renameableCpt = here.component "renameableCpt" cpt
T.write_ text state T.write_ text state
pure $ H.div { className: "renameable" } [ pure $ H.div { className: "renameable" } [
renameableText { isEditing, onRename, state } [] renameableText { isEditing, onRename, state, icon } []
] ]
type RenameableTextProps = type RenameableTextProps =
...@@ -47,6 +47,7 @@ type RenameableTextProps = ...@@ -47,6 +47,7 @@ type RenameableTextProps =
isEditing :: T.Box Boolean isEditing :: T.Box Boolean
, onRename :: String -> Effect Unit , onRename :: String -> Effect Unit
, state :: T.Box String , state :: T.Box String
, icon :: String
) )
renameableText :: R2.Component RenameableTextProps renameableText :: R2.Component RenameableTextProps
...@@ -58,9 +59,9 @@ renameableTextCpt = here.component "renameableText" cpt ...@@ -58,9 +59,9 @@ renameableTextCpt = here.component "renameableText" cpt
isEditing' <- T.useLive T.unequal isEditing isEditing' <- T.useLive T.unequal isEditing
pure $ if isEditing' then pure $ if isEditing' then
notEditing props []
else
editing props [] editing props []
else
notEditing props []
notEditing :: R2.Component RenameableTextProps notEditing :: R2.Component RenameableTextProps
...@@ -68,15 +69,13 @@ notEditing = R.createElement notEditingCpt ...@@ -68,15 +69,13 @@ notEditing = R.createElement notEditingCpt
notEditingCpt :: R.Component RenameableTextProps notEditingCpt :: R.Component RenameableTextProps
notEditingCpt = here.component "notEditing" cpt notEditingCpt = here.component "notEditing" cpt
where where
cpt { isEditing, state } _ = do cpt { isEditing, state, icon} _ = do
state' <- T.useLive T.unequal state state' <- T.useLive T.unequal state
pure $ H.div { className: "input-group" } pure $ H.div { className: "input-group" }
[ H.input { className: "form-control" [ H.span {className: icon} []
, defaultValue: state' , H.text state'
, disabled: 1 , H.button { className: "btn input-group-append"
, type: "text" }
, H.div { className: "btn input-group-append"
, on: { click: \_ -> T.write_ true isEditing } } , on: { click: \_ -> T.write_ true isEditing } }
[ H.span { className: "fa fa-pencil" } [] [ H.span { className: "fa fa-pencil" } []
] ]
...@@ -88,11 +87,12 @@ editing = R.createElement editingCpt ...@@ -88,11 +87,12 @@ editing = R.createElement editingCpt
editingCpt :: R.Component RenameableTextProps editingCpt :: R.Component RenameableTextProps
editingCpt = here.component "editing" cpt editingCpt = here.component "editing" cpt
where where
cpt { isEditing, onRename, state } _ = do cpt { isEditing, onRename, state, icon } _ = do
state' <- T.useLive T.unequal state state' <- T.useLive T.unequal state
pure $ H.div { className: "input-group" } pure $ H.div { className: "input-group" }
[ inputWithEnter { [ H.span {className: icon} []
, inputWithEnter {
autoFocus: false autoFocus: false
, className: "form-control text" , className: "form-control text"
, defaultValue: state' , defaultValue: state'
...@@ -102,8 +102,8 @@ editingCpt = here.component "editing" cpt ...@@ -102,8 +102,8 @@ editingCpt = here.component "editing" cpt
, placeholder: "" , placeholder: ""
, type: "text" , type: "text"
} }
, H.div { className: "btn input-group-append" , H.button { className: "btn input-group-append"
, on: { click: submit } } , on: { click: submit state' } }
[ H.span { className: "fa fa-floppy-o" } [] [ H.span { className: "fa fa-floppy-o" } []
] ]
] ]
......
module Gargantext.Components.Table where module Gargantext.Components.Table where
import Gargantext.Prelude
import Data.Array as A import Data.Array as A
import Data.Either (Either(..))
import Data.Maybe (Maybe(..)) import Data.Maybe (Maybe(..))
import Data.Sequence as Seq import Data.Sequence as Seq
import Effect (Effect) import Effect (Effect)
import Reactix as R import Effect.Aff (launchAff_)
import Reactix.DOM.HTML as H import Effect.Class (liftEffect)
import Toestand as T
import Gargantext.Prelude
import Gargantext.Components.FolderView as FV import Gargantext.Components.FolderView as FV
import Gargantext.Components.Table.Types (ColumnName, OrderBy, OrderByDirection(..), Params, Props, TableContainerProps, columnName) import Gargantext.Components.Forest.Tree.Node.Action.Rename (RenameValue(..), rename)
import Gargantext.Components.Nodes.Corpus (saveCorpus)
import Gargantext.Components.Nodes.Corpus.Types (CorpusInfo(..), Hyperdata(..), getCorpusInfo, saveCorpusInfo)
import Gargantext.Components.Nodes.Lists.Types as NT import Gargantext.Components.Nodes.Lists.Types as NT
import Gargantext.Components.Nodes.Types (FTFieldList)
import Gargantext.Components.Renameable (renameable)
import Gargantext.Components.Search (SearchType(..)) import Gargantext.Components.Search (SearchType(..))
import Gargantext.Utils.Reactix as R2 import Gargantext.Components.Table.Types (ColumnName, OrderBy, OrderByDirection(..), Params, Props, TableContainerProps, columnName)
import Gargantext.Sessions.Types (Session)
import Gargantext.Types (NodeID)
import Gargantext.Utils.Reactix (effectLink) import Gargantext.Utils.Reactix (effectLink)
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
here = R2.here "Gargantext.Components.Table" here = R2.here "Gargantext.Components.Table"
...@@ -51,10 +60,155 @@ type TableHeaderLayoutProps = ( ...@@ -51,10 +60,155 @@ type TableHeaderLayoutProps = (
, user :: String , user :: String
) )
type TableHeaderWithRenameLayoutProps = (
cacheState :: T.Box NT.CacheState
, session :: Session
, hyperdata :: Hyperdata
, nodeId :: NodeID
, name :: String
, date :: String
, key :: String
)
type TableHeaderWithRenameBoxedLayoutProps = (
cacheState :: T.Box NT.CacheState
, session :: Session
, hyperdata :: Hyperdata
, nodeId :: NodeID
, name :: String
, date :: String
, key :: String
, corpusInfoS :: T.Box CorpusInfo
)
initialParams :: Params initialParams :: Params
initialParams = stateParams {page: 1, pageSize: PS10, orderBy: Nothing, searchType: SearchDoc} initialParams = stateParams {page: 1, pageSize: PS10, orderBy: Nothing, searchType: SearchDoc}
-- TODO: Not sure this is the right place for this -- TODO: Not sure this is the right place for this
tableHeaderWithRenameLayout :: R2.Component TableHeaderWithRenameLayoutProps
tableHeaderWithRenameLayout = R.createElement tableHeaderWithRenameLayoutCpt
tableHeaderWithRenameLayoutCpt :: R.Component TableHeaderWithRenameLayoutProps
tableHeaderWithRenameLayoutCpt = here.component "tableHeaderWithRenameLayoutCpt" cpt
where
cpt { hyperdata: Hyperdata h, nodeId, session, cacheState, name, date, key } _ = do
let corpusInfo = getCorpusInfo h.fields
corpusInfoS <- T.useBox corpusInfo
pure $ tableHeaderWithRenameBoxedLayout {hyperdata: Hyperdata h, nodeId, session, cacheState, name, date, corpusInfoS, key} []
tableHeaderWithRenameBoxedLayout :: R2.Component TableHeaderWithRenameBoxedLayoutProps
tableHeaderWithRenameBoxedLayout = R.createElement tableHeaderWithRenameBoxedLayoutCpt
tableHeaderWithRenameBoxedLayoutCpt :: R.Component TableHeaderWithRenameBoxedLayoutProps
tableHeaderWithRenameBoxedLayoutCpt = here.component "tableHeaderWithRenameBoxedLayoutCpt" cpt
where
cpt { hyperdata: Hyperdata h, nodeId, session, cacheState, name, date, corpusInfoS} _ = do
cacheState' <- T.useLive T.unequal cacheState
CorpusInfo {title, desc, query, authors} <- T.read corpusInfoS
pure $ R.fragment
[ R2.row [FV.backButton {} []]
,
R2.row
[ H.div {className: "col-md-3"} [ H.h3 {} [renameable {icon: "", text: name, onRename: onRenameCorpus} []] ]
, H.div {className: "col-md-9"}
[ H.hr {style: {height: "2px", backgroundColor: "black"}} ]
]
, R2.row
[ H.div {className: "col-md-8 content"}
[ H.p {}
[
renameable {icon: "fa fa-info", text: title, onRename: onRenameTitle} []
]
, H.p {}
[
renameable {icon: "fa fa-globe", text: desc, onRename: onRenameDesc} []
]
, H.p {}
[
renameable {icon: "fa fa-search-plus", text: query, onRename: onRenameQuery} []
]
, H.p { className: "cache-toggle"
, on: { click: cacheClick cacheState } }
[ H.span { className: "fa " <> (cacheToggle cacheState') } []
, H.text $ cacheText cacheState'
]
]
, H.div {className: "col-md-4 content"}
[ H.p {}
[
renameable {icon: "fa fa-user", text: authors, onRename: onRenameAuthors} []
]
, H.p {}
[ H.span {className: "fa fa-calendar"} []
, H.text $ " " <> date
]
]
]
]
where
onRenameCorpus newName = do
saveCorpusName {name: newName, session, nodeId}
onRenameTitle newTitle = do
_ <- T.modify (\(CorpusInfo c) -> CorpusInfo $ c {title = newTitle}) corpusInfoS
corpusInfo <- T.read corpusInfoS
let newFields = saveCorpusInfo corpusInfo h.fields
save {fields: newFields, session, nodeId}
onRenameDesc newDesc = do
_ <- T.modify (\(CorpusInfo c) -> CorpusInfo $ c {desc = newDesc}) corpusInfoS
corpusInfo <- T.read corpusInfoS
let newFields = saveCorpusInfo corpusInfo h.fields
save {fields: newFields, session, nodeId}
onRenameQuery newQuery = do
_ <- T.modify (\(CorpusInfo c) -> CorpusInfo $ c {query = newQuery}) corpusInfoS
corpusInfo <- T.read corpusInfoS
let newFields = saveCorpusInfo corpusInfo h.fields
save {fields: newFields, session, nodeId}
onRenameAuthors newAuthors = do
_ <- T.modify (\(CorpusInfo c) -> CorpusInfo $ c {authors = newAuthors}) corpusInfoS
corpusInfo <- T.read corpusInfoS
let newFields = saveCorpusInfo corpusInfo h.fields
save {fields: newFields, session, nodeId}
cacheToggle NT.CacheOn = "fa-toggle-on"
cacheToggle NT.CacheOff = "fa-toggle-off"
cacheText NT.CacheOn = "Cache On"
cacheText NT.CacheOff = "Cache Off"
cacheClick cacheState _ = do
T.modify cacheStateToggle cacheState
cacheStateToggle NT.CacheOn = NT.CacheOff
cacheStateToggle NT.CacheOff = NT.CacheOn
save :: {fields :: FTFieldList, session :: Session, nodeId :: Int} -> Effect Unit
save {fields, session, nodeId} = do
launchAff_ do
res <- saveCorpus $ {hyperdata: Hyperdata {fields}, session, nodeId}
liftEffect $ do
_ <- case res of
Left err -> here.log2 "[corpusLayoutView] onClickSave RESTError" err
_ -> pure unit
pure unit
saveCorpusName :: {name :: String, session :: Session, nodeId :: Int} -> Effect Unit
saveCorpusName {name, session, nodeId} = do
launchAff_ do
res <- rename session nodeId $ RenameValue {text: name}
liftEffect $ do
_ <- case res of
Left err -> here.log2 "[corpusLayoutView] onClickSave RESTError" err
_ -> pure unit
pure unit
tableHeaderLayout :: R2.Component TableHeaderLayoutProps tableHeaderLayout :: R2.Component TableHeaderLayoutProps
tableHeaderLayout = R.createElement tableHeaderLayoutCpt tableHeaderLayout = R.createElement tableHeaderLayoutCpt
tableHeaderLayoutCpt :: R.Component TableHeaderLayoutProps tableHeaderLayoutCpt :: R.Component TableHeaderLayoutProps
...@@ -89,13 +243,13 @@ tableHeaderLayoutCpt = here.component "tableHeaderLayout" cpt ...@@ -89,13 +243,13 @@ tableHeaderLayoutCpt = here.component "tableHeaderLayout" cpt
] ]
, H.div {className: "col-md-4 content"} , H.div {className: "col-md-4 content"}
[ H.p {} [ H.p {}
[ H.span {className: "fa fa-calendar"} []
, H.text $ " " <> date
]
, H.p {}
[ H.span {className: "fa fa-user"} [] [ H.span {className: "fa fa-user"} []
, H.text $ " " <> user , H.text $ " " <> user
] ]
, H.p {}
[ H.span {className: "fa fa-calendar"} []
, H.text $ " " <> date
]
] ]
] ]
] ]
......
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