module Gargantext.Components.Forest.Tree.Node.Box where import Data.Array as A import Data.Maybe (Maybe(..)) import Data.Tuple (fst) import Data.Tuple.Nested ((/\)) import DOM.Simple.Console (log2) import Effect.Aff (Aff) import Reactix as R import Reactix.DOM.HTML as H import Gargantext.Prelude 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.Delete (actionDelete) import Gargantext.Components.Forest.Tree.Node.Action.Documentation (actionDoc) import Gargantext.Components.Forest.Tree.Node.Action.Download (actionDownload) import Gargantext.Components.Forest.Tree.Node.Action.Rename (renameAction) import Gargantext.Components.Forest.Tree.Node.Action.Search (actionSearch) import Gargantext.Components.Forest.Tree.Node.Action.Search.SearchField (defaultSearch) import Gargantext.Components.Forest.Tree.Node.Action.Share as Share import Gargantext.Components.Forest.Tree.Node.Action.Contact as Contact import Gargantext.Components.Forest.Tree.Node.Action.Update (update) import Gargantext.Components.Forest.Tree.Node.Action.Upload (actionUpload) import Gargantext.Components.Forest.Tree.Node.Action.Move (moveNode) import Gargantext.Components.Forest.Tree.Node.Action.Link (linkNode) import Gargantext.Components.Forest.Tree.Node.Action.Merge (mergeNode) 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, prettyNodeType) import Gargantext.Sessions (Session) import Gargantext.Types (Name, ID) import Gargantext.Types as GT import Gargantext.Utils (glyphicon, glyphiconActive) import Gargantext.Utils.Reactix as R2 thisModule = "Gargantext.Components.Forest.Tree.Node.Box" type CommonProps = ( dispatch :: Action -> Aff Unit , session :: Session ) -- | START Popup View nodePopupView :: Record NodePopupProps -> R.Element nodePopupView p = R.createElement nodePopupCpt p [] nodePopupCpt :: R.Component NodePopupProps nodePopupCpt = R.hooksComponentWithModule thisModule "nodePopupView" cpt where cpt p _ = do isOpen <- R.useState' false nodePopupState@(nodePopup /\ setNodePopup) <- R.useState' { action : Nothing , id : p.id , name : p.name , nodeType: p.nodeType } search <- R.useState' $ defaultSearch { node_id = Just p.id } R.useEffect' $ do log2 "[nodePopup] nodePopupState" $ fst nodePopupState pure $ H.div tooltipProps $ [ H.div { className: "popup-container" } [ H.div { className: "panel panel-default" } [ H.div {className: ""} [ H.div { className : "col-md-10 flex-between"} [ H.h3 { className: GT.fldr p.nodeType true} [] -- TODO fix names , H.text $ prettyNodeType p.nodeType , H.p {className: "text-primary center"} [H.text p.name] ] ] , panelHeading isOpen p , panelBody nodePopupState p , mPanelAction nodePopupState p ] ] ] where tooltipProps = { className : "" , id : "node-popup-tooltip" , title : "Node settings" , data: { toggle : "tooltip" , placement: "right" } --, style: { top: y - 65.0, left: x + 10.0 } } panelHeading isOpen@(open /\ _) {dispatch, id, name, nodeType} = H.div {className: "panel-heading"} [ R2.row [ H.div {className: "col-md-8 flex-end"} [ textInputBox { boxAction: renameAction , boxName: "Rename" , dispatch , id , text:name , isOpen } ] , H.div {className: "flex-end"} [ if edit then editIcon isOpen else H.div {} [] , H.div {className: "col-md-1"} [ H.a { "type" : "button" , className: glyphicon "window-close" , on : { click: \e -> p.onPopoverClose $ R.unsafeEventTarget e } , title : "Close" } [] ] ] ] ] where SettingsBox {edit, doc, buttons} = settingsBox nodeType editIcon :: R.State Boolean -> R.Element editIcon (false /\ setIsOpen) = H.div {className : "col-md-1"} [ H.a { className: glyphicon "pencil" , id : "rename1" , title : "Rename" , on: { click: \_ -> setIsOpen $ const true } } [] ] editIcon (true /\ _) = H.div {} [] panelBody :: R.State (Record ActionState) -> Record NodePopupProps -> R.Element panelBody nodePopupState {dispatch: d, nodeType} = H.div {className: "panel-body flex-space-between"} $ [ H.p { className: "spacer" } [] , H.div { className: "flex-center" } [ buttonClick { action: doc , state: nodePopupState , nodeType } ] , H.div {className: "flex-center"} $ map (\t -> buttonClick { action: t , state : nodePopupState , nodeType } ) buttons ] -- FIXME trick to increase the size of the box <> if A.length buttons < 2 then [H.div {className: "col-md-4"} []] else [] where SettingsBox {edit, doc, buttons} = settingsBox nodeType mPanelAction :: R.State (Record NodePopupS) -> Record NodePopupProps -> R.Element mPanelAction ({action: Nothing } /\ _) _ = H.div {className:"center fa-hand-pointer-o"} [ H.h4 {} [H.text " Select available actions of this node"] , H.ul {} [ H.h5 {style:{color:"black"} , className: "fa-thumbs-o-up" } [H.text " Black: yes you can use it" ] , H.h5 {style:{color:"orange"}, className: "fa-exclamation-triangle"} [H.text " Orange: almost useable" ] , H.h5 {style:{color:"red"} , className: "fa-rocket" } [H.text " Red: development in progress" ] ] ] mPanelAction ({action: Just action} /\ _) props = panelAction { action , dispatch : props.dispatch , id : props.id , name : props.name , nodePopup: Just NodePopup , nodeType : props.nodeType , session : props.session , handed : props.handed } type ActionState = ( action :: Maybe NodeAction , id :: ID , name :: Name , nodeType :: GT.NodeType ) type ButtonClickProps = ( action :: NodeAction , state :: R.State (Record ActionState) , nodeType :: GT.NodeType ) buttonClick :: Record ButtonClickProps -> R.Element buttonClick p = R.createElement buttonClickCpt p [] buttonClickCpt :: R.Component ButtonClickProps buttonClickCpt = R.hooksComponentWithModule thisModule "buttonClick" cpt where cpt {action: todo, state: (node@{action} /\ setNodePopup), nodeType} _ = do pure $ H.div {className: "col-md-1"} [ H.a { style: (iconAStyle nodeType todo) , className: glyphiconActive (glyphiconNodeAction todo) (action == (Just todo) ) , id: show todo , title: show todo , on: { click: \_ -> doToDo } } [] ] where -- | Open the help indications if selected already doToDo = setNodePopup $ const $ node { action = todo' } where todo' = case action == Just todo of true -> Nothing false -> Just todo iconAStyle :: GT.NodeType -> NodeAction -> { color :: String , paddingTop :: String , paddingBottom :: String } iconAStyle n a = { color : hasColor (hasStatus n a) , paddingTop : "6px" , paddingBottom : "6px" } where hasColor :: Status -> String hasColor Stable = "black" hasColor Test = "orange" hasColor Dev = "red" -- END Popup View type NodeProps = ( id :: ID , name :: Name , nodeType :: GT.NodeType ) type PanelActionProps = ( id :: ID , action :: NodeAction , dispatch :: Action -> Aff Unit , name :: Name , nodePopup :: Maybe NodePopup , nodeType :: GT.NodeType , session :: Session , handed :: GT.Handed ) panelAction :: Record PanelActionProps -> R.Element panelAction p = R.createElement panelActionCpt p [] panelActionCpt :: R.Component PanelActionProps panelActionCpt = R.hooksComponentWithModule thisModule "panelAction" cpt where cpt {action: Documentation nodeType} _ = actionDoc nodeType cpt {action: Download, id, nodeType, session} _ = actionDownload nodeType id session cpt {action: Upload, dispatch, id, nodeType, session} _ = actionUpload nodeType id session dispatch cpt {action: Delete, nodeType, dispatch} _ = actionDelete nodeType dispatch cpt {action: Add xs, dispatch, id, name, nodeType} _ = do pure $ addNodeView {dispatch, id, name, nodeType, nodeTypes: xs} cpt {action: Refresh , dispatch, id, nodeType, session} _ = update nodeType dispatch cpt {action: Config , dispatch, id, nodeType, session} _ = do pure $ fragmentPT $ "Config " <> show nodeType ----------- -- Functions using SubTree cpt {action: Merge {subTreeParams}, dispatch, id, nodeType, session, handed} _ = do pure $ mergeNode {dispatch, id, nodeType, session, subTreeParams, handed} cpt {action: Move {subTreeParams}, dispatch, id, nodeType, session, handed} _ = do pure $ moveNode {dispatch, id, nodeType, session, subTreeParams, handed} cpt {action: Link {subTreeParams}, dispatch, id, nodeType, session, handed} _ = do pure $ linkNode {dispatch, id, nodeType, session, subTreeParams, handed} ----------- cpt {action : Share, dispatch, id, name } _ = do isOpen <- R.useState' true pure $ H.div {} [ textInputBox { boxAction: Share.shareAction , boxName: "Share" , dispatch , id , text: "username" , isOpen } ] cpt {action : AddingContact, dispatch, id, name } _ = do isOpen <- R.useState' true pure $ Contact.textInputBox { id , dispatch , isOpen , boxName:"addContact" , params : {firstname:"First Name", lastname: "Last Name"} , boxAction: \p -> AddContact p } cpt {action : Publish {subTreeParams}, dispatch, id, nodeType, session, handed} _ = do pure $ Share.shareNode {dispatch, id, nodeType, session, subTreeParams, handed} cpt props@{action: SearchBox, id, session, dispatch, nodePopup} _ = actionSearch session (Just id) dispatch nodePopup cpt _ _ = do pure $ H.div {} []