module Gargantext.Components.Forest.Tree.Node.Box where import Gargantext.Prelude import Data.Array as A import Data.Foldable (intercalate) import Data.Maybe (Maybe(..)) import Effect.Aff (Aff) import Gargantext.Components.App.Store (Boxes) import Gargantext.Components.Bootstrap as B import Gargantext.Components.Bootstrap.Types (ComponentStatus(..), Elevation(..)) import Gargantext.Components.Forest.Tree.Node.Action.Add (addNodeView) import Gargantext.Components.Forest.Tree.Node.Action.Contact as Contact 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.Link (linkNode) import Gargantext.Components.Forest.Tree.Node.Action.ManageTeam (actionManageTeam) import Gargantext.Components.Forest.Tree.Node.Action.Merge (mergeNode) import Gargantext.Components.Forest.Tree.Node.Action.Move (moveNode) 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.Share as Share import Gargantext.Components.Forest.Tree.Node.Action.Types (Action) 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.WriteNodesDocuments (actionWriteNodesDocuments) 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 (fragmentPT, textInputBox) import Gargantext.Sessions (Session) import Gargantext.Types (ID, Name, prettyNodeType) import Gargantext.Types as GT import Gargantext.Utils ((?)) 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.Box" type CommonProps = ( dispatch :: Action -> Aff Unit , session :: Session ) nodePopupView :: R2.Leaf NodePopupProps nodePopupView = R2.leaf nodePopupViewCpt nodePopupViewCpt :: R.Component NodePopupProps nodePopupViewCpt = here.component "nodePopupView" cpt where cpt p@{ id, name, nodeType } _ = do renameIsOpen <- T.useBox false open <- T.useLive T.unequal renameIsOpen nodePopup <- T.useBox { action: Nothing, id, name, nodeType } action <- T.useFocused (_.action) (\a b -> b { action = a }) nodePopup nodePopup' <- T.useLive T.unequal nodePopup pure $ H.div { className: "node-popup-tooltip" , title: "Type: " <> prettyNodeType nodeType } [ H.div { className: "popup-container card" } [ panelHeading renameIsOpen open p , panelBody action p , mPanelAction nodePopup' p ] ] panelHeading renameIsOpen open p@{ dispatch, id, name, nodeType } = H.div { className: "popup-container__header card-header" } [ B.wad [ "d-flex", "align-items-center" ] [ B.wad [ "w-2/12" ] [ H.span { className: GT.fldr nodeType true} [] -- TODO fix names -- , -- B.span' { className: "small" } $ prettyNodeType nodeType ] , B.wad [ "w-8/12 text-center" ] [ if open then textInputBox { boxAction: renameAction , boxName: "Rename" , dispatch , id , text: name , isOpen: renameIsOpen } [] else B.wad' [ "text-primary" ] p.name ] , B.wad [ "w-2/12", "text-right" ] [ editIcon renameIsOpen open , B.wad_ [ "d-inline-block", "w-3" ] , B.iconButton { callback: const $ p.closeCallback unit , title: "Close" , name: "times" , elevation: Level2 } ] ] ] editIcon _ true = mempty editIcon isOpen false = B.iconButton { name: "pencil" , title: "Rename" , callback: const $ T.write_ true isOpen , elevation: Level2 } panelBody :: T.Box (Maybe NodeAction) -> Record NodePopupProps -> R.Element panelBody nodePopupState { nodeType } = let (SettingsBox { doc, buttons }) = settingsBox nodeType in H.div { className: intercalate " " [ "popup-container__body" , "card-body" ] } $ [ buttonClick { action: doc , state: nodePopupState , nodeType } ] <> ( buttons <#> \t -> buttonClick { action: t , state: nodePopupState , nodeType } ) -- FIXME trick to increase the size of the box <> if A.length buttons < 2 then [ H.div { className: "col-4" } [] ] else [] mPanelAction :: Record NodePopupS -> Record NodePopupProps -> R.Element mPanelAction { action: Just action } { boxes, dispatch, id, name, nodeType, session } = panelAction { action , boxes , dispatch , id , name , nodeType , session } mPanelAction { action: Nothing } _ = H.div { className: "popup-container__footer card-footer" } [ H.h6 {} [ B.icon { name: "hand-pointer-o" , className: "mr-1" } , H.text "Select available actions of this node" ] , H.ul { className: "panel-actions" } [ H.div { className: "panel-actions__ok-to-use" } [ B.icon { name: "circle" } , B.span_ "usable" ] , H.div { className: "panel-actions__almost-useable" } [ B.icon { name: "circle" } , B.span_ "almost useable" ] , H.div { className: "panel-actions__development-in-progress" } [ B.icon { name: "circle" } , B.span_ "development in progress" ] ] ] type ActionState = ( action :: Maybe NodeAction , id :: ID , name :: Name , nodeType :: GT.NodeType ) type ButtonClickProps = ( action :: NodeAction , state :: T.Box (Maybe NodeAction) , nodeType :: GT.NodeType ) buttonClick :: R2.Leaf ButtonClickProps buttonClick = R2.leaf buttonClickCpt buttonClickCpt :: R.Component ButtonClickProps buttonClickCpt = here.component "buttonClick" cpt where cpt { action: todo , state , nodeType } _ = do -- | States -- | action <- R2.useLive' state -- | Behaviors -- | let click _ = T.write_ (Just todo) state -- | Render pure $ -- B.iconButton -- { className: intercalate " " -- [ "popup-container__body__button" -- , modifierClassName (hasStatus nodeType todo) -- ] -- , name: glyphiconNodeAction todo -- , title: show todo -- , callback: click -- , elevation: Level2 -- , status: action == Just todo ? -- Disabled $ -- Enabled -- } H.div { className: intercalate " " [ "popup-container__cta" , modifierClassName (hasStatus nodeType todo) ] } [ B.iconButton { className: "popup-container__cta__button" , name: glyphiconNodeAction todo , title: show todo , callback: click , elevation: Level2 , status: action == Just todo ? Disabled $ Enabled } , B.icon { className: "popup-container__cta__icon" , name: "circle" } ] -- | Helpers -- | modifierClassName :: Status -> String modifierClassName = case _ of Stable -> blk <> "--ok-to-use" Test -> blk <> "--almost-useable" Dev -> blk <> "--development-in-progress" where blk = "popup-container__cta" type NodeProps = ( id :: ID , name :: Name , nodeType :: GT.NodeType ) type PanelActionProps = ( action :: NodeAction , boxes :: Boxes , id :: ID , dispatch :: Action -> Aff Unit , name :: Name , nodeType :: GT.NodeType , session :: Session ) panelAction :: R2.Leaf PanelActionProps panelAction = R2.leaf panelActionCpt panelActionCpt :: R.Component PanelActionProps panelActionCpt = here.component "panelAction" cpt where cpt { action: Add xs, dispatch, id, name, nodeType} _ = pure $ addNodeView {dispatch, id, name, nodeType, nodeTypes: xs} [] cpt { action : AddingContact, dispatch, id } _ = pure $ Contact.actionAddContact { dispatch, id } [] cpt { action: Config, nodeType } _ = pure $ fragmentPT $ "Config " <> show nodeType cpt { action: Delete, nodeType, dispatch} _ = pure $ actionDelete { dispatch, nodeType } [] cpt { action: Documentation nodeType} _ = pure $ actionDoc { nodeType } [] cpt { action: Download, id, nodeType, session} _ = pure $ actionDownload { id, nodeType, session } [] cpt { action: Link {subTreeParams}, boxes, dispatch, id, nodeType, session } _ = pure $ linkNode { boxes, dispatch, id, nodeType, session, subTreeParams } [] cpt { action: ManageTeam, boxes, nodeType, id, session} _ = pure $ actionManageTeam { boxes, id, nodeType, session } [] cpt { action: Merge {subTreeParams}, boxes, dispatch, id, nodeType, session } _ = pure $ mergeNode { boxes, dispatch, id, nodeType, session, subTreeParams } [] cpt { action: Move {subTreeParams}, boxes, dispatch, id, nodeType, session } _ = pure $ moveNode { boxes, dispatch, id, nodeType, session, subTreeParams } [] cpt { action : Publish {subTreeParams}, boxes, dispatch, id, nodeType, session } _ = pure $ Share.publishNode { boxes, dispatch, id, nodeType, session, subTreeParams } [] cpt { action: Reconstruct , dispatch, nodeType } _ = pure $ update { dispatch, nodeType } [] cpt { action: Refresh , dispatch, nodeType } _ = pure $ update { dispatch, nodeType } [] cpt { action: ReloadWithSettings , dispatch, nodeType } _ = pure $ update { dispatch, nodeType } [] cpt { action: SearchBox, boxes, dispatch, id, session } _ = pure $ actionSearch { boxes, dispatch, id: Just id, session } [] cpt { action : Share, id, session } _ = pure $ Share.shareNode { id, session } [] cpt { action: Upload, dispatch, id, nodeType, session} _ = pure $ actionUpload { dispatch, id, nodeType, session } [] cpt { action: WriteNodesDocuments, boxes, dispatch, id, session } _ = pure $ actionWriteNodesDocuments { boxes, dispatch, id, session } [] cpt _ _ = pure $ H.div {} []