module Gargantext.Components.Forest.Tree.Node.Tools where import Data.Maybe (fromMaybe, Maybe(..)) import Data.Nullable (null) import Data.Set (Set) import Data.Set as Set import Data.String as S import Data.String.CodeUnits as DSCU import Data.Tuple.Nested ((/\)) import Effect (Effect) import Effect.Aff (Aff, launchAff, launchAff_) import Reactix as R import Reactix.DOM.HTML as H import Gargantext.Prelude import Gargantext.Components.Forest.Tree.Node.Action import Gargantext.Components.InputWithEnter (inputWithEnter) import Gargantext.Ends (Frontends, url) import Gargantext.Sessions (Session, sessionId) import Gargantext.Types (ID, Name) import Gargantext.Types as GT import Gargantext.Utils (toggleSet) import Gargantext.Utils.Reactix as R2 import Gargantext.Utils.ReactTooltip as ReactTooltip thisModule = "Gargantext.Components.Forest.Tree.Node.Tools" ------------------------------------------------------------------------ type Body = Array R.Element type Footer = R.Element panel :: Body -> Footer -> R.Element panel bodies submit = H.div {} [ panelBody bodies, footer submit ] where panelBody bs = H.div {className: "panel-body"} [ H.div { className: "row spacer" } [ H.div { className: "col-md-12" } bs -- TODO add type for text or form here -- [ H.form {className: "form-horizontal"} bs ] ] ] footer sb = H.div {className: "panel-footer"} [ H.div {} [] , H.div { className: "center"} [ sb ] ] ------------------------------------------------------------------------ -- | START Text input type TextInputBoxProps = ( id :: ID , dispatch :: Action -> Aff Unit , text :: String , isOpen :: R.State Boolean , boxName :: String , boxAction :: String -> Action ) textInputBox :: Record TextInputBoxProps -> R.Element textInputBox p@{ boxName, boxAction, dispatch, isOpen: (true /\ setIsOpen) } = R.createElement el p [] where el = R2.hooksComponent thisModule (boxName <> "Box") cpt cpt {id, text} _ = do renameNodeName <- R.useState' text pure $ H.div {className: "from-group row-no-padding"} [ textInput renameNodeName , submitBtn renameNodeName , cancelBtn ] where textInput (newName /\ setNewName) = H.div {className: "col-md-8"} [ inputWithEnter { onEnter: submit newName , onValueChanged: setNewName <<< const , autoFocus: false , className: "form-control" , defaultValue: text , placeholder: (boxName <> " Node") , type: "text" } -- [ H.input { type: "text" -- , placeholder: (boxName <> " Node") -- , defaultValue: text -- , className: "form-control" -- , on: { input: setRenameNodeName -- <<< const -- <<< R2.unsafeEventValue } -- } ] submitBtn (newName /\ _) = H.a {className: "btn glyphitem glyphicon glyphicon-ok col-md-2 pull-left" , type: "button" , on: { click: submit newName } , title: "Submit" } [] cancelBtn = H.a {className: "btn text-danger glyphitem glyphicon glyphicon-remove col-md-2 pull-left" , type: "button" , on: { click: \_ -> setIsOpen $ const false } , title: "Cancel" } [] submit newName _ = do setIsOpen $ const false launchAff_ $ dispatch ( boxAction newName ) textInputBox p@{ boxName, isOpen: (false /\ _) } = R.createElement el p [] where el = R2.hooksComponent thisModule (boxName <> "Box") cpt cpt {text} _ = pure $ H.div {} [] -- | END Rename Box -- | Sugar Text style fragmentPT :: String -> R.Element fragmentPT text = H.div {style: {margin: "10px"}} [H.text text] -- | Form Edit input type DefaultText = String formEdit :: forall previous next . DefaultText -> ((previous -> String) -> Effect next) -> R.Element formEdit defaultValue setter = H.div {className: "form-group"} [ H.input { type : "text" , placeholder : defaultValue , defaultValue: defaultValue , className : "form-control" , on: { input: setter <<< const <<< R2.unsafeEventValue } } ] -- | Form Choice input -- if the list of options is not big enough, a button is used instead formChoiceSafe :: forall a b c . Read a => Show a => Array a -> a -> ((b -> a) -> Effect c) -> R.Element formChoiceSafe [] _ _ = H.div {} [] formChoiceSafe [n] _defaultNodeType setNodeType = formButton n setNodeType formChoiceSafe nodeTypes defaultNodeType setNodeType = formChoice nodeTypes defaultNodeType setNodeType -- | List Form formChoice :: forall a b c d . Read b => Show d => Array d -> b -> ((c -> b) -> Effect a) -> R.Element formChoice nodeTypes defaultNodeType setNodeType = H.div { className: "form-group"} [ R2.select { className: "form-control" , on: { change: setNodeType <<< const <<< fromMaybe defaultNodeType <<< read <<< R2.unsafeEventValue } } (map (\opt -> H.option {} [ H.text $ show opt ]) nodeTypes) ] -- | Button Form -- FIXME: currently needs a click from the user (by default, we could avoid such click) formButton :: forall a b c . Show a => a -> ((b -> a) -> Effect c) -> R.Element formButton nodeType setNodeType = H.div {} [ H.text $ "Confirm the selection of: " <> show nodeType , bouton ] where bouton = H.button { className : "cold-md-5 btn btn-primary center" , type : "button" , title: "Form Button" , style : { width: "100%" } , on: { click: \_ -> setNodeType ( const nodeType ) } } [H.text $ "Confirmation"] ------------------------------------------------------------------------ ------------------------------------------------------------------------ submitButton :: Action -> (Action -> Aff Unit) -> R.Element submitButton action dispatch = H.button { className : "btn btn-primary fa fa-" <> icon action , type: "button" , style : { width: "50%" } , id: S.toLower $ show action , title: show action , on: {click: \_ -> launchAff $ dispatch action} } [ H.text $ " " <> text action] type Href = String submitButtonHref :: Action -> Href -> R.Element submitButtonHref action href = H.a { className : "btn btn-primary fa fa-" <> icon action , style : { width: "50%" } , href , target: "_blank" } [ H.text $ " " <> text action] ------------------------------------------------------------------------ -- | CheckBox tools -- checkboxes: Array of poolean values (basic: without pending option) -- checkbox : One boolean value only checkbox :: R.State Boolean -> R.Element checkbox ( val /\ set ) = H.input { id: "checkbox-id" , type: "checkbox" , value: val , className : "checkbox" , on: { click: \_ -> set $ const $ not val} } data CheckBoxes = Multiple | Uniq checkboxes :: forall a . Ord a => Show a => Array a -> R.State (Set a) -> R.Element checkboxes xs (val /\ set) = H.fieldset {} $ map (\a -> H.div {} [ H.input { type: "checkbox" , checked: Set.member a val , on: { click: \_ -> set $ const $ toggleSet a val } } , H.div {} [H.text $ show a] ] ) xs prettyNodeType :: GT.NodeType -> String prettyNodeType nt = S.replace (S.Pattern "Node") (S.Replacement " ") $ S.replace (S.Pattern "Folder") (S.Replacement " ") $ show nt -- START node link type NodeLinkProps = ( frontends :: Frontends , id :: Int , folderOpen :: R.State Boolean , isSelected :: Boolean , name :: Name , nodeType :: GT.NodeType , session :: Session , handed :: GT.Handed ) nodeLink :: Record NodeLinkProps -> R.Element nodeLink p = R.createElement nodeLinkCpt p [] nodeLinkCpt :: R.Component NodeLinkProps nodeLinkCpt = R2.hooksComponent thisModule "nodeLink" cpt where cpt { frontends, id, isSelected, name, nodeType, session, handed, folderOpen} _ = do popoverRef <- R.useRef null pure $ H.div { onClick: R2.effToggler folderOpen } [ H.a { data: { for: tooltipId , tip: true } , href: url frontends $ GT.NodePath (sessionId session) nodeType (Just id) } [ nodeText { isSelected , name , handed } ] , ReactTooltip.reactTooltip { id: tooltipId } [ R2.row [ H.h4 {className: GT.fldr nodeType true} [ H.text $ prettyNodeType nodeType ] ] , R2.row [ H.span {} [ H.text $ name ]] ] ] where tooltipId = "node-link-" <> show id -- END node link -- START node text type NodeTextProps = ( isSelected :: Boolean , name :: Name , handed :: GT.Handed ) nodeText :: Record NodeTextProps -> R.Element nodeText p = R.createElement nodeTextCpt p [] nodeTextCpt :: R.Component NodeTextProps nodeTextCpt = R2.hooksComponent thisModule "nodeText" cpt where cpt { isSelected: true, name } _ = do pure $ H.u {} [ H.b {} [ H.text ("| " <> name15 name <> " | ") ] ] cpt {isSelected: false, name, handed} _ = do pure $ if handed == GT.RightHanded then H.text "..." <> H.text (name15 name) else H.text (name15 name) <> H.text "..." name len n = if S.length n < len then n else case (DSCU.slice 0 len n) of Nothing -> "???" Just s -> s <> "..." name15 = name 15 -- END node text ------------------------------------------------------------------------