From 9f93eb2b50f79e7b73dcd48a804c402991d7e694 Mon Sep 17 00:00:00 2001 From: Przemek Kaminski <pk@intrepidus.pl> Date: Wed, 19 Feb 2020 11:37:47 +0100 Subject: [PATCH] [forest] refactor node popup view --- .../Components/Forest/Tree/Node.purs | 5 + .../Forest/Tree/Node/Action/Upload.purs | 11 +- .../Components/Forest/Tree/Node/Box.purs | 166 ++++++++++-------- 3 files changed, 111 insertions(+), 71 deletions(-) diff --git a/src/Gargantext/Components/Forest/Tree/Node.purs b/src/Gargantext/Components/Forest/Tree/Node.purs index d86b7806..2fedcd01 100644 --- a/src/Gargantext/Components/Forest/Tree/Node.purs +++ b/src/Gargantext/Components/Forest/Tree/Node.purs @@ -22,6 +22,7 @@ data NodeAction = Documentation NodeType | Move | Clone | Delete | Share | Link NodeType | Add (Array NodeType) + | CopyFromCorpus instance eqNodeAction :: Eq NodeAction where @@ -36,6 +37,7 @@ instance eqNodeAction :: Eq NodeAction where eq Share Share = true eq (Link x) (Link y) = true && (x == y) eq (Add x) (Add y) = true && (x == y) + eq CopyFromCorpus CopyFromCorpus = true eq _ _ = false instance showNodeAction :: Show NodeAction where @@ -50,6 +52,7 @@ instance showNodeAction :: Show NodeAction where show Share = "Share" show (Link x) = "Link to " <> show x show (Add xs) = foldl (\a b -> a <> show b) "Add " xs + show CopyFromCorpus = "Copy from corpus" glyphiconNodeAction :: NodeAction -> String @@ -60,6 +63,7 @@ glyphiconNodeAction SearchBox = "search" glyphiconNodeAction Upload = "upload" glyphiconNodeAction (Link _) = "transfer" glyphiconNodeAction Download = "download" +glyphiconNodeAction CopyFromCorpus = "random" glyphiconNodeAction _ = "" @@ -183,6 +187,7 @@ settingsBox NodeList = SettingsBox { , edit : false , doc : Documentation NodeList , buttons : [ Upload + , CopyFromCorpus , Download , Delete ] diff --git a/src/Gargantext/Components/Forest/Tree/Node/Action/Upload.purs b/src/Gargantext/Components/Forest/Tree/Node/Action/Upload.purs index 2e741150..6c79bcb1 100644 --- a/src/Gargantext/Components/Forest/Tree/Node/Action/Upload.purs +++ b/src/Gargantext/Components/Forest/Tree/Node/Action/Upload.purs @@ -33,7 +33,7 @@ uploadFileView :: (Action -> Aff Unit) -> Record Props -> R.Element uploadFileView d props = R.createElement (uploadFileViewCpt d) props [] uploadFileViewCpt :: (Action -> Aff Unit) -> R.Component Props -uploadFileViewCpt d = R.hooksComponent "UploadFileView" cpt +uploadFileViewCpt d = R.hooksComponent "G.C.F.T.N.A.U.UploadFileView" cpt where cpt {id, nodeType} _ = do mContents :: R.State (Maybe UploadFileContents) <- R.useState' Nothing @@ -234,3 +234,12 @@ uploadFile session nodeType id fileType (UploadFileContents fileContents) = do Tuple "_wf_data" (Just fileContents) , Tuple "_wf_filetype" (Just $ show fileType) ] + +uploadTermListView :: (Action -> Aff Unit) -> Record Props -> R.Element +uploadTermListView d props = R.createElement (uploadFileViewCpt d) props [] + +uploadTermListViewCpt :: (Action -> Aff Unit) -> R.Component Props +uploadTermListViewCpt d = R.hooksComponent "G.C.F.T.N.A.U.UploadTermListView" cpt + where + cpt {id, nodeType} _ = do + pure $ H.div {} [ H.text "Upload term list" ] diff --git a/src/Gargantext/Components/Forest/Tree/Node/Box.purs b/src/Gargantext/Components/Forest/Tree/Node/Box.purs index a3b15df1..ee74d942 100644 --- a/src/Gargantext/Components/Forest/Tree/Node/Box.purs +++ b/src/Gargantext/Components/Forest/Tree/Node/Box.purs @@ -21,7 +21,7 @@ import Gargantext.Components.Forest.Tree.Node (NodeAction(..), SettingsBox(..), import Gargantext.Components.Forest.Tree.Node.Action (Action(..), DroppedFile(..), FileType(..), ID, Name, UploadFileContents(..)) import Gargantext.Components.Forest.Tree.Node.Action.Add (NodePopup(..), createNodeView) import Gargantext.Components.Forest.Tree.Node.Action.Rename (renameBox) -import Gargantext.Components.Forest.Tree.Node.Action.Upload (uploadFileView, fileTypeView) +import Gargantext.Components.Forest.Tree.Node.Action.Upload (uploadFileView, fileTypeView, uploadTermListView) import Gargantext.Components.Forest.Tree.Node.ProgressBar (asyncProgressBar) import Gargantext.Components.Data.Lang (allLangs, Lang(EN)) import Gargantext.Components.Search.SearchBar (searchBar) @@ -104,13 +104,15 @@ nodeMainSpan d p folderOpen session frontends = R.createElement el p [] mNodePopupView _ _ (Nothing /\ _) _ = H.div {} [] mNodePopupView _ _ _ (Nothing /\ _) = H.div {} [] mNodePopupView props@{asyncTasks, id, nodeType} true popupOpen (Just position /\ _) = - nodePopupView d { id - , action: Nothing - , name: name' props - , nodeType - , position - , session - } popupOpen + nodePopupView { id + , action: Nothing + , dispatch: d + , name: name' props + , nodePopupState: popupOpen + , nodeType + , position + , session + } dropProps droppedFile isDragOver = { className: dropClass droppedFile isDragOver @@ -182,7 +184,9 @@ mCorpusId _ = Nothing type NodePopupProps = ( id :: ID , action :: Maybe NodeAction + , dispatch :: Action -> Aff Unit , name :: Name + , nodePopupState :: R.State (Maybe NodePopup) , nodeType :: GT.NodeType , position :: R2.Point , session :: Session @@ -194,35 +198,43 @@ iconAStyle = { color : "black" , paddingBottom : "6px" } -nodePopupView :: (Action -> Aff Unit) - -> Record NodePopupProps - -> R.State (Maybe NodePopup) - -> R.Element -nodePopupView d p mPop@(Just NodePopup /\ setPopupOpen) = R.createElement el p [] +nodePopupView :: Record NodePopupProps -> R.Element +nodePopupView p = R.createElement nodePopupCpt p [] + +nodePopupCpt :: R.Component NodePopupProps +nodePopupCpt = R.hooksComponent "G.C.F.T.N.B.nodePopupView" cpt where - el = R.hooksComponent "NodePopupView" cpt - cpt {id, action, name, nodeType, position, session} _ = do + cpt p@{nodePopupState: mPop@(Just NodePopup /\ setPopupOpen)} _ = do renameBoxOpen <- R.useState' false - nodePopupState@(nodePopup /\ setNodePopup) <- R.useState' {id, name, nodeType, action} - search <- R.useState' $ defaultSearch { node_id = Just id } - pure $ H.div (tooltipProps position) $ + nodePopupState@(nodePopup /\ setNodePopup) <- R.useState' {action: p.action, id: p.id, name: p.name, nodeType: p.nodeType} + search <- R.useState' $ defaultSearch { node_id = Just p.id } + pure $ H.div (tooltipProps p.position) $ [ H.div {id: "arrow"} [] , H.div { className: "popup-container" } [ H.div { className: "panel panel-default" } [ H.div {className: ""} [ H.div { className : "col-md-11"} - [ H.h3 { className: GT.fldr nodeType true} [H.text $ show nodeType] - , H.p {className: "text-primary center"} [H.text name] + [ H.h3 { className: GT.fldr p.nodeType true} [H.text $ show p.nodeType] + , H.p {className: "text-primary center"} [H.text p.name] ] ] - , panelHeading renameBoxOpen - , panelBody nodePopupState d - , panelAction d {id, name, nodeType, action:nodePopup.action, session, search} mPop + , panelHeading renameBoxOpen p + , panelBody nodePopupState p + , panelAction { + action: nodePopup.action + , dispatch: p.dispatch + , id: p.id + , name: p.name + , nodePopupState: mPop + , nodeType: p.nodeType + , search + , session: p.session + } ] , if nodePopup.action == Just SearchBox then H.div {} [ - searchIsTexIframe id session search + searchIsTexIframe p search ] else H.div {} [] @@ -238,16 +250,7 @@ nodePopupView d p mPop@(Just NodePopup /\ setPopupOpen) = R.createElement el p [ style: { top: y - 65.0, left: x + 10.0 } } - SettingsBox {edit, doc, buttons} = settingsBox nodeType - - removeCircleGeneral (Just _) setNodePopup = removeCircle setNodePopup - removeCircleGeneral Nothing _ = H.div {} [] - removeCircle setNodePopup = - H.div { className: glyphicon "remove-circle" - , onClick : setNodePopup $ const {id, name, nodeType, action :Nothing} - } [] - - panelHeading renameBoxOpen@(open /\ _) = + panelHeading renameBoxOpen@(open /\ _) {dispatch: d, id, name, nodeType} = H.div {className: "panel-heading"} [ R2.row [ H.div {className: "col-md-8"} @@ -266,6 +269,7 @@ nodePopupView d p mPop@(Just NodePopup /\ setPopupOpen) = R.createElement el p [ ] ] where + SettingsBox {edit, doc, buttons} = settingsBox nodeType editIcon (false /\ setRenameBoxOpen) = H.div {className : "col-md-1"} [ H.a { className: glyphicon "pencil" @@ -278,14 +282,16 @@ nodePopupView d p mPop@(Just NodePopup /\ setPopupOpen) = R.createElement el p [ ] editIcon (true /\ _) = H.div {} [] - panelBody nodePopupState d' = + panelBody nodePopupState {dispatch: d, nodeType} = H.div {className: "panel-body flex-space-between"} - [ H.div {className: "flex-center"} [buttonClick nodePopupState d' doc] + [ H.div {className: "flex-center"} [buttonClick nodePopupState d doc] , H.div {className: "flex-center"} - $ map (buttonClick nodePopupState d') buttons + $ map (buttonClick nodePopupState d) buttons ] + where + SettingsBox {edit, doc, buttons} = settingsBox nodeType - searchIsTexIframe _id _session search@(search' /\ _) = + searchIsTexIframe {nodeType} search@(search' /\ _) = if isIsTex search'.datafield then H.div { className: "istex-search panel panel-default" } [ @@ -307,9 +313,6 @@ nodePopupView d p mPop@(Just NodePopup /\ setPopupOpen) = R.createElement el p [ Tuple (NQP.keyFromString "query") (Just (NQP.valueFromString term)) ] -nodePopupView _ p _ = R.createElement el p [] - where - el = R.hooksComponent "CreateNodeView" cpt cpt _ _ = pure $ H.div {} [] @@ -352,44 +355,67 @@ type Open = Boolean type PanelActionProps = ( id :: ID , action :: Maybe NodeAction + , dispatch :: Action -> Aff Unit , name :: Name + , nodePopupState :: R.State (Maybe NodePopup) , nodeType :: GT.NodeType , session :: Session , search :: R.State Search ) -panelAction :: (Action -> Aff Unit) - -> Record PanelActionProps - -> R.State (Maybe NodePopup) - -> R.Element -panelAction d {id, name, nodeType, action, session, search} p = case action of - (Just (Documentation GT.NodeUser)) -> R.fragment [H.div {style: {margin: "10px"}} [ infoTitle GT.NodeUser - , H.p {} [ H.text "This account is personal"] - , H.p {} [ H.text "See the instances terms of uses."] - ] - ] - (Just (Documentation GT.FolderPrivate)) -> fragmentPT "This folder and its children are private only!" - (Just (Documentation GT.FolderPublic)) -> fragmentPT "Soon, you will be able to build public folders to share your work with the world!" - (Just (Documentation GT.FolderShared)) -> fragmentPT "Soon, you will be able to build teams folders to share your work" - (Just (Documentation x)) -> fragmentPT $ "More information on" <> show nodeType - - (Just (Link _)) -> fragmentPT "Soon, you will be able to link the corpus with your Annuaire (and reciprocally)." - (Just Upload) -> uploadFileView d {id, nodeType, session} - (Just Download) -> fragmentPT "Soon, you will be able to dowload your file here" - - (Just SearchBox) -> R.fragment [ H.p {"style": {"margin" :"10px"}} [ H.text $ "Search and create a private corpus with the search query as corpus name." ] - , searchBar {langs: allLangs, onSearch, search, session} - ] - (Just Delete) -> case nodeType of - GT.NodeUser -> R.fragment [ H.div {style: {margin: "10px"}} [H.text "Yes, we are RGPD compliant! But you can not delete User Node yet (we are still on development). Thanks for your comprehensin."]] - _ -> R.fragment [ H.div {style: {margin: "10px"}} (map (\t -> H.p {} [H.text t]) ["Are your sure you want to delete it ?", "If yes, click again below."]), reallyDelete d] - (Just (Add xs)) -> createNodeView d {id, name, nodeType} p xs - _ -> H.div {} [] +panelAction :: Record PanelActionProps -> R.Element +panelAction p = R.createElement panelActionCpt p [] + +panelActionCpt :: R.Component PanelActionProps +panelActionCpt = R.hooksComponent "G.C.F.T.N.B.panelAction" cpt where + cpt {action: Just (Documentation GT.NodeUser)} _ = do + pure $ R.fragment [ + H.div {style: {margin: "10px"}} [ infoTitle GT.NodeUser + , H.p {} [ H.text "This account is personal"] + , H.p {} [ H.text "See the instances terms of uses."] + ] + ] + cpt {action: Just (Documentation GT.FolderPrivate)} _ = do + pure $ fragmentPT "This folder and its children are private only!" + cpt {action: Just (Documentation GT.FolderPublic)} _ = do + pure $ fragmentPT "Soon, you will be able to build public folders to share your work with the world!" + cpt {action: Just (Documentation GT.FolderShared)} _ = do + pure $ fragmentPT "Soon, you will be able to build teams folders to share your work" + cpt {action: Just (Documentation x), nodeType} _ = do + pure $ fragmentPT $ "More information on" <> show nodeType + + cpt {action: Just (Link _)} _ = do + pure $ fragmentPT "Soon, you will be able to link the corpus with your Annuaire (and reciprocally)." + cpt {action: Just Upload, dispatch: d, id, nodeType: GT.NodeList, session} _ = do + pure $ uploadTermListView d {id, nodeType: GT.NodeList, session} + cpt {action: Just Upload, dispatch: d, id, nodeType, session} _ = do + pure $ uploadFileView d {id, nodeType, session} + cpt {action: Just Download} _ = do + pure $ fragmentPT "Soon, you will be able to dowload your file here" + cpt props@{action: Just SearchBox, search, session} _ = do + pure $ R.fragment [ + H.p {"style": {"margin" :"10px"}} [ H.text $ "Search and create a private corpus with the search query as corpus name." ] + , searchBar {langs: allLangs, onSearch: onSearch props, search, session} + ] + cpt {action: Just Delete, nodeType: GT.NodeUser} _ = do + pure $ R.fragment [ + H.div {style: {margin: "10px"}} [H.text "Yes, we are RGPD compliant! But you can not delete User Node yet (we are still on development). Thanks for your comprehensin."] + ] + cpt {action: Just Delete, dispatch: d} _ = do + pure $ R.fragment [ + H.div {style: {margin: "10px"}} (map (\t -> H.p {} [H.text t]) ["Are your sure you want to delete it ?", "If yes, click again below."]) + , reallyDelete d + ] + cpt {action: Just (Add xs), dispatch: d, id, name, nodePopupState: p, nodeType} _ = do + pure $ createNodeView d {id, name, nodeType} p xs + cpt _ _ = do + pure $ H.div {} [] + fragmentPT text = H.div {style: {margin: "10px"}} [H.text text] - onSearch :: GT.AsyncTaskWithType -> Effect Unit - onSearch task = do + onSearch :: Record PanelActionProps -> GT.AsyncTaskWithType -> Effect Unit + onSearch {dispatch: d, nodePopupState: p} task = do _ <- launchAff $ d (SearchQuery task) -- close popup snd p $ const Nothing -- 2.21.0