Commit 10932f5b authored by Alexandre Delanoë's avatar Alexandre Delanoë

Merge branch 'dev-warnings-cleanup' into dev

parents bfc60431 9e296c86
...@@ -15,9 +15,9 @@ ...@@ -15,9 +15,9 @@
} }
#graph-explorer .graph-tree { #graph-explorer .graph-tree {
position: absolute; position: absolute;
top: 120px;
max-height: 600px; max-height: 600px;
overflow-y: scroll; overflow-y: scroll;
top: 150px;
z-index: 1; z-index: 1;
} }
#graph-explorer #graph-view { #graph-explorer #graph-view {
...@@ -25,13 +25,13 @@ ...@@ -25,13 +25,13 @@
} }
#graph-explorer #sp-container { #graph-explorer #sp-container {
position: absolute; position: absolute;
left: 70%; max-height: 600px;
overflow-y: scroll;
top: 150px; top: 150px;
z-index: 1; z-index: 1;
left: 70%;
border: 1px white solid; border: 1px white solid;
background-color: white; background-color: white;
max-height: 600px;
overflow-y: scroll;
} }
#graph-explorer #sp-container #myTab { #graph-explorer #sp-container #myTab {
marginBottom: 18px; marginBottom: 18px;
...@@ -50,4 +50,13 @@ ...@@ -50,4 +50,13 @@
z-index: 1; z-index: 1;
} }
.input-with-autocomplete .completions {
position: absolute;
max-height: 300px;
overflow-y: scroll;
width: 300px;
top: 50px;
z-index: 5;
}
/*# sourceMappingURL=Graph.css.map */ /*# sourceMappingURL=Graph.css.map */
@mixin sidePanelCommon
position: absolute
max-height: 600px
overflow-y: scroll
top: 150px
z-index: 1
#graph-explorer #graph-explorer
#toolbar #toolbar
display: flex display: flex
...@@ -14,24 +21,16 @@ ...@@ -14,24 +21,16 @@
height: 79px height: 79px
.graph-tree .graph-tree
position: absolute @include sidePanelCommon
top: 120px
max-height: 600px
overflow-y: scroll
z-index: 1
#graph-view #graph-view
height: 95% height: 95%
#sp-container #sp-container
position: absolute @include sidePanelCommon
left: 70% left: 70%
top: 150px
z-index: 1
border: 1px white solid border: 1px white solid
background-color: white background-color: white
max-height: 600px
overflow-y: scroll
#myTab #myTab
marginBottom: 18px marginBottom: 18px
...@@ -49,3 +48,12 @@ ...@@ -49,3 +48,12 @@
#tree #tree
position: absolute position: absolute
z-index: 1 z-index: 1
.input-with-autocomplete
.completions
position: absolute
max-height: 300px
overflow-y: scroll
width: 300px
top: 50px
z-index: 5
...@@ -204,7 +204,7 @@ li:hover a#rename-leaf { ...@@ -204,7 +204,7 @@ li:hover a#rename-leaf {
justify-content: center; justify-content: center;
} }
.flex-center { .flex-space-between, .flex-center {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
} }
......
...@@ -188,8 +188,7 @@ li ...@@ -188,8 +188,7 @@ li
flew-wrap: wrap flew-wrap: wrap
justify-content: center justify-content: center
.flex-space-between .flex-space-between,.flex-center
.flex-center
display: flex display: flex
justify-content: space-between justify-content: space-between
......
...@@ -16,9 +16,9 @@ import Data.Maybe (Maybe(..), maybe) ...@@ -16,9 +16,9 @@ import Data.Maybe (Maybe(..), maybe)
import Data.Set (Set) import Data.Set (Set)
import Data.Set as Set import Data.Set as Set
import Data.Symbol (SProxy(..)) import Data.Symbol (SProxy(..))
import Data.Tuple (Tuple(..), fst, snd) import Data.Tuple (Tuple(..), fst)
import Data.Tuple.Nested ((/\)) import Data.Tuple.Nested ((/\))
import DOM.Simple.Console (log, log3) import DOM.Simple.Console (log3)
import DOM.Simple.Event as DE import DOM.Simple.Event as DE
import Effect (Effect) import Effect (Effect)
import Effect.Aff (Aff, launchAff) import Effect.Aff (Aff, launchAff)
...@@ -28,11 +28,10 @@ import Reactix.DOM.HTML as H ...@@ -28,11 +28,10 @@ import Reactix.DOM.HTML as H
------------------------------------------------------------------------ ------------------------------------------------------------------------
import Gargantext.Components.Table as T import Gargantext.Components.Table as T
import Gargantext.Components.Loader (loader) import Gargantext.Components.Loader (loader)
import Gargantext.Components.Table as T
import Gargantext.Ends (Frontends, url) import Gargantext.Ends (Frontends, url)
import Gargantext.Utils.Reactix as R2 import Gargantext.Utils.Reactix as R2
import Gargantext.Routes as Routes import Gargantext.Routes as Routes
import Gargantext.Routes (AppRoute, SessionRoute(NodeAPI)) import Gargantext.Routes (SessionRoute(NodeAPI))
import Gargantext.Sessions (Session, sessionId, post, delete, put) import Gargantext.Sessions (Session, sessionId, post, delete, put)
import Gargantext.Types (NodeType(..), OrderBy(..), TabType, TabPostQuery(..), AffTableResult) import Gargantext.Types (NodeType(..), OrderBy(..), TabType, TabPostQuery(..), AffTableResult)
------------------------------------------------------------------------ ------------------------------------------------------------------------
......
...@@ -11,7 +11,7 @@ import Gargantext.Components.Forest.Tree.Node.Action (Action(..), ID, Name) ...@@ -11,7 +11,7 @@ import Gargantext.Components.Forest.Tree.Node.Action (Action(..), ID, Name)
import Gargantext.Components.Forest.Tree.Node (SettingsBox(..), settingsBox) import Gargantext.Components.Forest.Tree.Node (SettingsBox(..), settingsBox)
import Gargantext.Types (NodeType(..), readNodeType) import Gargantext.Types (NodeType(..), readNodeType)
import Gargantext.Utils.Reactix as R2 import Gargantext.Utils.Reactix as R2
import Prelude (Unit, bind, const, discard, map, pure, show, ($), (<>), (>)) import Prelude (Unit, bind, const, discard, map, pure, show, ($), (<>), (>), (<<<))
import Reactix as R import Reactix as R
import Reactix.DOM.HTML as H import Reactix.DOM.HTML as H
...@@ -54,29 +54,24 @@ createNodeView d p@{nodeType} (_ /\ setPopupOpen) nodeTypes = R.createElement el ...@@ -54,29 +54,24 @@ createNodeView d p@{nodeType} (_ /\ setPopupOpen) nodeTypes = R.createElement el
] ]
where where
SettingsBox {edit} = settingsBox nt SettingsBox {edit} = settingsBox nt
maybeEdit = [ if edit maybeEdit = [ if edit then
then
H.div {className: "form-group"} H.div {className: "form-group"}
[ H.input { type: "text" [ H.input { type: "text"
, placeholder: "Node name" , placeholder: "Node name"
, defaultValue: "Write Name here" , defaultValue: "Write Name here"
, className: "form-control" , className: "form-control"
, onInput: mkEffectFn1 $ \e -> setNodeName , onInput: mkEffectFn1 $ setNodeName <<< const <<< R2.unsafeEventValue
$ const
$ e .. "target" .. "value"
} }
] ]
else else
H.div {} [] H.div {} []
] ]
maybeChoose = [ if length nodeTypes > 1 maybeChoose = [ if length nodeTypes > 1 then
then R.fragment [
R.fragment [H.div {className: "form-group"} $ [ R2.select { className: "form-control" H.div {className: "form-group"} $ [
, onChange: mkEffectFn1 $ \e -> setNodeType R2.select { className: "form-control"
$ const , onChange: mkEffectFn1 $ setNodeType <<< const <<< readIt <<< R2.unsafeEventValue
$ readIt
$ e .. "target" .. "value"
} }
(map (\opt -> H.option {} [ H.text $ show opt ]) nodeTypes) (map (\opt -> H.option {} [ H.text $ show opt ]) nodeTypes)
] ]
......
...@@ -3,13 +3,14 @@ module Gargantext.Components.Forest.Tree.Node.Action.Rename where ...@@ -3,13 +3,14 @@ module Gargantext.Components.Forest.Tree.Node.Action.Rename where
import Data.Tuple.Nested ((/\)) import Data.Tuple.Nested ((/\))
import Effect.Aff (Aff, launchAff) import Effect.Aff (Aff, launchAff)
import Effect.Uncurried (mkEffectFn1) import Effect.Uncurried (mkEffectFn1)
import FFI.Simple ((..)) import Prelude (Unit, bind, const, discard, pure, ($), (<<<))
import Gargantext.Components.Forest.Tree.Node.Action
import Gargantext.Types (NodeType)
import Prelude (Unit, bind, const, discard, pure, ($))
import Reactix as R import Reactix as R
import Reactix.DOM.HTML as H import Reactix.DOM.HTML as H
import Gargantext.Components.Forest.Tree.Node.Action
import Gargantext.Types (NodeType)
import Gargantext.Utils.Reactix as R2
-- | START Rename Box -- | START Rename Box
type RenameBoxProps = type RenameBoxProps =
...@@ -35,7 +36,7 @@ renameBox d p (true /\ setRenameBoxOpen) = R.createElement el p [] ...@@ -35,7 +36,7 @@ renameBox d p (true /\ setRenameBoxOpen) = R.createElement el p []
, placeholder: "Rename Node" , placeholder: "Rename Node"
, defaultValue: name , defaultValue: name
, className: "form-control" , className: "form-control"
, onInput: mkEffectFn1 $ \e -> setRenameNodeName $ const $ e .. "target" .. "value" , onInput: mkEffectFn1 $ setRenameNodeName <<< const <<< R2.unsafeEventValue
} }
] ]
renameBtn (newName /\ _) = renameBtn (newName /\ _) =
......
...@@ -64,7 +64,7 @@ uploadFileViewCpt d = R.hooksComponent "UploadFileView" cpt ...@@ -64,7 +64,7 @@ uploadFileViewCpt d = R.hooksComponent "UploadFileView" cpt
setMContents $ const $ Just $ UploadFileContents contents setMContents $ const $ Just $ UploadFileContents contents
onChangeFileType (fileType /\ setFileType) = mkEffectFn1 $ \e -> do onChangeFileType (fileType /\ setFileType) = mkEffectFn1 $ \e -> do
setFileType $ const $ unsafePartial $ fromJust $ readFileType $ e .. "target" .. "value" setFileType $ const $ unsafePartial $ fromJust $ readFileType $ R2.unsafeEventValue e
uploadButton :: Int -> R.State (Maybe UploadFileContents) -> R.State FileType -> R.Element uploadButton :: Int -> R.State (Maybe UploadFileContents) -> R.State FileType -> R.Element
uploadButton id (mContents /\ setMContents) (fileType /\ setFileType) = uploadButton id (mContents /\ setMContents) (fileType /\ setFileType) =
...@@ -131,7 +131,7 @@ fileTypeView d p (Just (DroppedFile {contents, fileType}) /\ setDroppedFile) (_ ...@@ -131,7 +131,7 @@ fileTypeView d p (Just (DroppedFile {contents, fileType}) /\ setDroppedFile) (_
] ]
where where
onChange = mkEffectFn1 $ \e -> onChange = mkEffectFn1 $ \e ->
setDroppedFile $ const $ Just $ DroppedFile $ {contents, fileType: readFileType $ e .. "target" .. "value"} setDroppedFile $ const $ Just $ DroppedFile $ {contents, fileType: readFileType $ R2.unsafeEventValue e}
renderOption opt = H.option {} [ H.text $ show opt ] renderOption opt = H.option {} [ H.text $ show opt ]
panelFooter = panelFooter =
H.div {className: "panel-footer"} H.div {className: "panel-footer"}
......
...@@ -32,6 +32,7 @@ type Props sigma forceatlas2 = ...@@ -32,6 +32,7 @@ type Props sigma forceatlas2 =
, graph :: SigmaxTypes.SGraph , graph :: SigmaxTypes.SGraph
, multiSelectEnabledRef :: R.Ref Boolean , multiSelectEnabledRef :: R.Ref Boolean
, selectedNodeIds :: R.State SigmaxTypes.SelectedNodeIds , selectedNodeIds :: R.State SigmaxTypes.SelectedNodeIds
, selectorSize :: R.State Int
, showEdges :: R.State SigmaxTypes.ShowEdgesState , showEdges :: R.State SigmaxTypes.ShowEdgesState
, sigmaRef :: R.Ref Sigmax.Sigma , sigmaRef :: R.Ref Sigmax.Sigma
, sigmaSettings :: sigma , sigmaSettings :: sigma
...@@ -102,6 +103,10 @@ graphCpt = R.hooksComponent "Graph" cpt ...@@ -102,6 +103,10 @@ graphCpt = R.hooksComponent "Graph" cpt
Sigmax.updateNodes sigma tNodesMap Sigmax.updateNodes sigma tNodesMap
Sigmax.setEdges sigma (not $ SigmaxTypes.edgeStateHidden showEdges) Sigmax.setEdges sigma (not $ SigmaxTypes.edgeStateHidden showEdges)
-- R.useEffect1' (fst props.selectorSize) $ do
-- Sigmax.dependOnSigma (R.readRef sigmaRef) "[graphCpt (Ready)] no sigma" $ \sigma -> do
-- Sigmax.selectorWithSize sigma $ fst props.selectorSize
stageHooks _ = pure unit stageHooks _ = pure unit
......
...@@ -11,8 +11,6 @@ import Data.Nullable (null, Nullable) ...@@ -11,8 +11,6 @@ import Data.Nullable (null, Nullable)
import Data.Sequence as Seq import Data.Sequence as Seq
import Data.Set as Set import Data.Set as Set
import Data.Tuple (fst, snd, Tuple(..)) import Data.Tuple (fst, snd, Tuple(..))
import Data.Tuple.Nested ((/\))
import DOM.Simple.Console (log2)
import DOM.Simple.Types (Element) import DOM.Simple.Types (Element)
import Effect.Aff (Aff) import Effect.Aff (Aff)
import Math (log) import Math (log)
...@@ -191,6 +189,7 @@ graphViewCpt = R.hooksComponent "GraphView" cpt ...@@ -191,6 +189,7 @@ graphViewCpt = R.hooksComponent "GraphView" cpt
, graph , graph
, multiSelectEnabledRef , multiSelectEnabledRef
, selectedNodeIds: controls.selectedNodeIds , selectedNodeIds: controls.selectedNodeIds
, selectorSize: controls.selectorSize
, showEdges: controls.showEdges , showEdges: controls.showEdges
, sigmaRef: controls.sigmaRef , sigmaRef: controls.sigmaRef
, sigmaSettings: Graph.sigmaSettings , sigmaSettings: Graph.sigmaSettings
...@@ -204,16 +203,19 @@ convert (GET.GraphData r) = Tuple r.metaData $ SigmaxTypes.Graph {nodes, edges} ...@@ -204,16 +203,19 @@ convert (GET.GraphData r) = Tuple r.metaData $ SigmaxTypes.Graph {nodes, edges}
nodes = foldMapWithIndex nodeFn r.nodes nodes = foldMapWithIndex nodeFn r.nodes
nodeFn i (GET.Node n) = nodeFn i (GET.Node n) =
Seq.singleton Seq.singleton
{ id : n.id_ { borderColor: color
, size : log (toNumber n.size + 1.0) , color : color
, hidden : false , hidden : false
, id : n.id_
, label : n.label , label : n.label
, size : log (toNumber n.size + 1.0)
, type : "def" -- default type
, x : n.x -- cos (toNumber i) , x : n.x -- cos (toNumber i)
, y : n.y -- sin (toNumber i) , y : n.y -- sin (toNumber i)
, color : GET.intColor (cDef n.attributes)
} }
where where
cDef (GET.Cluster {clustDefault}) = clustDefault cDef (GET.Cluster {clustDefault}) = clustDefault
color = GET.intColor (cDef n.attributes)
nodesMap = SigmaxTypes.nodesMap nodes nodesMap = SigmaxTypes.nodesMap nodes
edges = foldMap edgeFn r.edges edges = foldMap edgeFn r.edges
edgeFn (GET.Edge e) = Seq.singleton { id : e.id_ edgeFn (GET.Edge e) = Seq.singleton { id : e.id_
...@@ -412,6 +414,6 @@ transformGraph controls graph = SigmaxTypes.Graph {nodes: newNodes, edges: newEd ...@@ -412,6 +414,6 @@ transformGraph controls graph = SigmaxTypes.Graph {nodes: newNodes, edges: newEd
_ -> edge _ -> edge
nodeMarked node@{ id } = nodeMarked node@{ id } =
if Set.member id (fst controls.selectedNodeIds) then if Set.member id (fst controls.selectedNodeIds) then
node { color = "#ff0000" } node { borderColor = "#000", type = "hovered" }
else else
node node
...@@ -43,6 +43,7 @@ type Controls = ...@@ -43,6 +43,7 @@ type Controls =
, multiSelectEnabled :: R.State Boolean , multiSelectEnabled :: R.State Boolean
, nodeSize :: R.State Range.NumberRange , nodeSize :: R.State Range.NumberRange
, selectedNodeIds :: R.State SigmaxTypes.SelectedNodeIds , selectedNodeIds :: R.State SigmaxTypes.SelectedNodeIds
, selectorSize :: R.State Int
, showControls :: R.State Boolean , showControls :: R.State Boolean
, showEdges :: R.State SigmaxTypes.ShowEdgesState , showEdges :: R.State SigmaxTypes.ShowEdgesState
, showSidePanel :: R.State GET.SidePanelState , showSidePanel :: R.State GET.SidePanelState
...@@ -60,7 +61,6 @@ type LocalControls = ...@@ -60,7 +61,6 @@ type LocalControls =
initialLocalControls :: R.Hooks (Record LocalControls) initialLocalControls :: R.Hooks (Record LocalControls)
initialLocalControls = do initialLocalControls = do
labelSize <- R.useState' 14.0 labelSize <- R.useState' 14.0
search <- R.useState' ""
pure $ { pure $ {
labelSize labelSize
...@@ -114,6 +114,16 @@ controlsCpt = R.hooksComponent "GraphControls" cpt ...@@ -114,6 +114,16 @@ controlsCpt = R.hooksComponent "GraphControls" cpt
else else
pure unit pure unit
let edgesConfluenceSorted = A.sortWith (_.confluence) $ Seq.toUnfoldable $ SigmaxTypes.graphEdges props.graph
let edgeConfluenceMin = maybe 0.0 _.confluence $ A.head edgesConfluenceSorted
let edgeConfluenceMax = maybe 100.0 _.confluence $ A.last edgesConfluenceSorted
let edgeConfluenceRange = Range.Closed { min: edgeConfluenceMin, max: edgeConfluenceMax }
let edgesWeightSorted = A.sortWith (_.weight) $ Seq.toUnfoldable $ SigmaxTypes.graphEdges props.graph
let edgeWeightMin = maybe 0.0 _.weight $ A.head edgesWeightSorted
let edgeWeightMax = maybe 100.0 _.weight $ A.last edgesWeightSorted
let edgeWeightRange = Range.Closed { min: edgeWeightMin, max: edgeWeightMax }
let nodesSorted = A.sortWith (_.size) $ Seq.toUnfoldable $ SigmaxTypes.graphNodes props.graph let nodesSorted = A.sortWith (_.size) $ Seq.toUnfoldable $ SigmaxTypes.graphNodes props.graph
let nodeSizeMin = maybe 0.0 _.size $ A.head nodesSorted let nodeSizeMin = maybe 0.0 _.size $ A.head nodesSorted
let nodeSizeMax = maybe 100.0 _.size $ A.last nodesSorted let nodeSizeMax = maybe 100.0 _.size $ A.last nodesSorted
...@@ -128,8 +138,8 @@ controlsCpt = R.hooksComponent "GraphControls" cpt ...@@ -128,8 +138,8 @@ controlsCpt = R.hooksComponent "GraphControls" cpt
RH.li {} [ centerButton props.sigmaRef ] RH.li {} [ centerButton props.sigmaRef ]
, RH.li {} [ pauseForceAtlasButton {state: props.forceAtlasState} ] , RH.li {} [ pauseForceAtlasButton {state: props.forceAtlasState} ]
, RH.li {} [ edgesToggleButton {state: props.showEdges} ] , RH.li {} [ edgesToggleButton {state: props.showEdges} ]
, RH.li {} [ edgeConfluenceControl props.sigmaRef props.edgeConfluence ] , RH.li {} [ edgeConfluenceControl edgeConfluenceRange props.edgeConfluence ]
, RH.li {} [ edgeWeightControl props.sigmaRef props.edgeWeight ] , RH.li {} [ edgeWeightControl edgeWeightRange props.edgeWeight ]
-- change level -- change level
-- file upload -- file upload
-- run demo -- run demo
...@@ -141,16 +151,14 @@ controlsCpt = R.hooksComponent "GraphControls" cpt ...@@ -141,16 +151,14 @@ controlsCpt = R.hooksComponent "GraphControls" cpt
-- zoom: 0 -100 - calculate ratio -- zoom: 0 -100 - calculate ratio
, RH.li {} [ multiSelectEnabledButton props.multiSelectEnabled ] -- toggle multi node selection , RH.li {} [ multiSelectEnabledButton props.multiSelectEnabled ] -- toggle multi node selection
-- save button -- save button
, RH.li {} [ nodeSearchControl { selectedNodeIds: props.selectedNodeIds } ] , RH.li {} [ nodeSearchControl { graph: props.graph
, selectedNodeIds: props.selectedNodeIds } ]
] ]
] ]
] ]
useGraphControls :: SigmaxTypes.SGraph -> R.Hooks (Record Controls) useGraphControls :: SigmaxTypes.SGraph -> R.Hooks (Record Controls)
useGraphControls graph = do useGraphControls graph = do
let edges = SigmaxTypes.graphEdges graph
let nodes = SigmaxTypes.graphNodes graph
cursorSize <- R.useState' 10.0 cursorSize <- R.useState' 10.0
edgeConfluence <- R.useState' $ Range.Closed { min: 0.0, max: 1.0 } edgeConfluence <- R.useState' $ Range.Closed { min: 0.0, max: 1.0 }
edgeWeight <- R.useState' $ Range.Closed { min: 0.0, max: 1.0 } edgeWeight <- R.useState' $ Range.Closed { min: 0.0, max: 1.0 }
...@@ -160,6 +168,7 @@ useGraphControls graph = do ...@@ -160,6 +168,7 @@ useGraphControls graph = do
nodeSize <- R.useState' $ Range.Closed { min: 0.0, max: 100.0 } nodeSize <- R.useState' $ Range.Closed { min: 0.0, max: 100.0 }
showTree <- R.useState' false showTree <- R.useState' false
selectedNodeIds <- R.useState' $ Set.empty selectedNodeIds <- R.useState' $ Set.empty
selectorSize <- R.useState' 5
showControls <- R.useState' false showControls <- R.useState' false
showEdges <- R.useState' SigmaxTypes.EShow showEdges <- R.useState' SigmaxTypes.EShow
showSidePanel <- R.useState' GET.InitialClosed showSidePanel <- R.useState' GET.InitialClosed
...@@ -175,6 +184,7 @@ useGraphControls graph = do ...@@ -175,6 +184,7 @@ useGraphControls graph = do
, multiSelectEnabled , multiSelectEnabled
, nodeSize , nodeSize
, selectedNodeIds , selectedNodeIds
, selectorSize
, showControls , showControls
, showEdges , showEdges
, showSidePanel , showSidePanel
......
...@@ -34,12 +34,12 @@ rangeControlCpt = R.hooksComponent "RangeButton" cpt ...@@ -34,12 +34,12 @@ rangeControlCpt = R.hooksComponent "RangeButton" cpt
, RS.rangeSlider sliderProps , RS.rangeSlider sliderProps
] ]
edgeConfluenceControl :: R.Ref Sigmax.Sigma -> R.State Range.NumberRange -> R.Element edgeConfluenceControl :: Range.NumberRange -> R.State Range.NumberRange -> R.Element
edgeConfluenceControl sigmaRef (state /\ setState) = edgeConfluenceControl (Range.Closed { min, max }) (state /\ setState) =
rangeControl { rangeControl {
caption: "Edge Confluence Weight" caption: "Edge Confluence Weight"
, sliderProps: { , sliderProps: {
bounds: Range.Closed { min: 0.0, max: 1.0 } bounds: Range.Closed { min, max }
, initialValue: state , initialValue: state
, epsilon: 0.01 , epsilon: 0.01
, step: 1.0 , step: 1.0
...@@ -49,47 +49,32 @@ edgeConfluenceControl sigmaRef (state /\ setState) = ...@@ -49,47 +49,32 @@ edgeConfluenceControl sigmaRef (state /\ setState) =
} }
} }
edgeWeightControl :: R.Ref Sigmax.Sigma -> R.State Range.NumberRange -> R.Element edgeWeightControl :: Range.NumberRange -> R.State Range.NumberRange -> R.Element
edgeWeightControl sigmaRef (state /\ setState) = edgeWeightControl (Range.Closed { min, max }) (state /\ setState) =
rangeControl { rangeControl {
caption: "Edge Weight" caption: "Edge Weight"
, sliderProps: { , sliderProps: {
bounds: Range.Closed { min: 0.0, max: 3.0 } bounds: Range.Closed { min, max }
, initialValue: state , initialValue: state
, epsilon: 0.01 , epsilon: 0.01
, step: 1.0 , step: 1.0
, width: 10.0 , width: 10.0
, height: 5.0 , height: 5.0
, onChange: setState <<< const , onChange: setState <<< const
-- , onChange: \range@(Range.Closed {min, max}) -> do
-- let sigma = R.readRef sigmaRef
-- Sigmax.dependOnSigma sigma "[edgeWeightControl] sigma: Nothing" $ \s -> do
-- Sigma.setSettings s {
-- minEdgeSize: min
-- , maxEdgeSize: max
-- }
-- setState $ const range
} }
} }
nodeSizeControl :: Range.NumberRange -> R.State Range.NumberRange -> R.Element nodeSizeControl :: Range.NumberRange -> R.State Range.NumberRange -> R.Element
nodeSizeControl (Range.Closed { min: rangeMin, max: rangeMax }) (state /\ setState) = nodeSizeControl (Range.Closed { min, max }) (state /\ setState) =
rangeControl { rangeControl {
caption: "Node Size" caption: "Node Size"
, sliderProps: { , sliderProps: {
bounds: Range.Closed { min: rangeMin, max: rangeMax } bounds: Range.Closed { min, max }
, initialValue: state , initialValue: state
, epsilon: 0.1 , epsilon: 0.1
, step: 1.0 , step: 1.0
, width: 10.0 , width: 10.0
, height: 5.0 , height: 5.0
, onChange: \range@(Range.Closed {min, max}) -> do , onChange: setState <<< const
-- let sigma = R.readRef sigmaRef
-- Sigmax.dependOnSigma sigma "[nodeSizeControl] sigma: Nothing" $ \s -> do
-- Sigma.setSettings s {
-- minNodeSize: min
-- , maxNodeSize: max
-- }
setState $ const range
} }
} }
...@@ -3,49 +3,70 @@ module Gargantext.Components.GraphExplorer.Search ...@@ -3,49 +3,70 @@ module Gargantext.Components.GraphExplorer.Search
, nodeSearchControl , nodeSearchControl
) where ) where
import Global (readFloat)
import Prelude import Prelude
import Data.Sequence as Seq
import Data.Set as Set import Data.Set as Set
import Data.Tuple (snd) import Data.String as S
import Data.Tuple.Nested ((/\)) import Data.Tuple.Nested ((/\))
import DOM.Simple.Console (log2) import DOM.Simple.Console (log2)
import Effect (Effect) import Effect (Effect)
import FFI.Simple ((..))
import Reactix as R import Reactix as R
import Reactix.DOM.HTML as H import Reactix.DOM.HTML as H
import Gargantext.Hooks.Sigmax as Sigmax import Gargantext.Components.InputWithAutocomplete (inputWithAutocomplete)
import Gargantext.Hooks.Sigmax.Sigma as Sigma
import Gargantext.Hooks.Sigmax.Types as SigmaxTypes import Gargantext.Hooks.Sigmax.Types as SigmaxTypes
import Gargantext.Utils.Reactix as R2
type Props = ( type Props = (
selectedNodeIds :: R.State SigmaxTypes.SelectedNodeIds graph :: SigmaxTypes.SGraph
, selectedNodeIds :: R.State SigmaxTypes.SelectedNodeIds
) )
-- | Whether a node matches a search string
nodeMatchesSearch :: String -> Record SigmaxTypes.Node -> Boolean
nodeMatchesSearch s n = S.contains (S.Pattern $ normalize s) (normalize n.label)
where
normalize = S.toLower
searchNodes :: String -> Seq.Seq (Record SigmaxTypes.Node) -> Seq.Seq (Record SigmaxTypes.Node)
searchNodes "" _ = Seq.empty
searchNodes s nodes = Seq.filter (nodeMatchesSearch s) nodes
nodeSearchControl :: Record Props -> R.Element nodeSearchControl :: Record Props -> R.Element
nodeSearchControl props = R.createElement sizeButtonCpt props [] nodeSearchControl props = R.createElement sizeButtonCpt props []
sizeButtonCpt :: R.Component Props sizeButtonCpt :: R.Component Props
sizeButtonCpt = R.hooksComponent "NodeSearchControl" cpt sizeButtonCpt = R.hooksComponent "NodeSearchControl" cpt
where where
cpt {selectedNodeIds} _ = do cpt {graph, selectedNodeIds} _ = do
(search /\ setSearch) <- R.useState' "" search@(search' /\ setSearch) <- R.useState' ""
pure $ pure $
H.div { className: "form-group" } H.div { className: "form-group" }
[ H.div { className: "input-group" } [ H.div { className: "input-group" }
[ H.input { type: "text" [ inputWithAutocomplete { autocompleteSearch: autocompleteSearch graph
, className: "form-control" , onAutocompleteClick: \s -> triggerSearch graph s selectedNodeIds
, defaultValue: search , onEnterPress: \s -> triggerSearch graph s selectedNodeIds
, on: { input: \e -> setSearch $ const $ e .. "target" .. "value" } , state: search }
}
, H.div { className: "btn input-group-addon" , H.div { className: "btn input-group-addon"
, on: { click: \_ -> log2 "[sizeButtonCpt] search" search } , on: { click: \_ -> triggerSearch graph search' selectedNodeIds }
} }
[ H.span { className: "fa fa-search" } [] ] [ H.span { className: "fa fa-search" } [] ]
] ]
] ]
-- TODO Wherefrom do I get graph nodes? autocompleteSearch :: SigmaxTypes.SGraph -> String -> Array String
-- How to implement filtering here? I want to set selectedNodeIds based on graph data. autocompleteSearch graph s = Seq.toUnfoldable $ (_.label) <$> searchNodes s nodes
where
nodes = SigmaxTypes.graphNodes graph
triggerSearch :: SigmaxTypes.SGraph
-> String
-> R.State SigmaxTypes.SelectedNodeIds
-> Effect Unit
triggerSearch graph search (_ /\ setSelectedNodeIds) = do
let nodes = SigmaxTypes.graphNodes graph
let matching = (_.id) <$> searchNodes search nodes
log2 "[triggerSearch] search" search
setSelectedNodeIds $ const $ Set.fromFoldable matching
...@@ -42,7 +42,7 @@ sidebarCpt = R.hooksComponent "Sidebar" cpt ...@@ -42,7 +42,7 @@ sidebarCpt = R.hooksComponent "Sidebar" cpt
let nodesMap = SigmaxTypes.nodesGraphMap props.graph let nodesMap = SigmaxTypes.nodesGraphMap props.graph
pure $ pure $
RH.div { id: "sp-container", className: "col-md-2" } RH.div { id: "sp-container", className: "col-md-3" }
[ RH.div {} [ RH.div {}
[ RH.div { className: "row" } [ RH.div { className: "row" }
[ RH.div { className: "col-md-12" } [ RH.div { className: "col-md-12" }
......
module Gargantext.Components.InputWithAutocomplete where
import Prelude
import Data.Maybe (Maybe(..))
import Data.Nullable (Nullable, null, toMaybe)
import Data.Tuple.Nested ((/\))
import DOM.Simple as DOM
import DOM.Simple.Event as DE
import Effect (Effect)
import Effect.Timer (setTimeout)
import Reactix as R
import Reactix.DOM.HTML as H
import Gargantext.Utils.Reactix as R2
type Completions = Array String
type Props =
(
autocompleteSearch :: String -> Completions
, onAutocompleteClick :: String -> Effect Unit
, onEnterPress :: String -> Effect Unit
, state :: R.State String
)
inputWithAutocomplete :: Record Props -> R.Element
inputWithAutocomplete props = R.createElement inputWithAutocompleteCpt props []
inputWithAutocompleteCpt :: R.Component Props
inputWithAutocompleteCpt = R.hooksComponent "InputWithAutocomplete" cpt
where
cpt props@{autocompleteSearch, onAutocompleteClick, onEnterPress, state: state@(state' /\ setState)} _ = do
inputRef <- R.useRef null
completions <- R.useState' $ autocompleteSearch state'
pure $
H.span { className: "input-with-autocomplete" }
[
completionsCpt completions
, H.input { type: "text"
, ref: inputRef
, className: "form-control"
, value: state'
, on: { blur: onBlur completions
, focus: onFocus completions
, input: onInput completions
, change: onInput completions
, keyUp: onInputKeyUp inputRef completions } }
]
where
-- setTimeout is a bit of a hack here -- clicking on autocomplete
-- element will clear out the blur first, so the autocomplete click
-- won't fire without a timeout here. However, blur is very handy and
-- handles automatic autocomplete search, otherwise I'd have to hide it
-- in various different places (i.e. carefully handle all possible
-- events where blur happens and autocomplete should hide).
onBlur (_ /\ setCompletions) e = setTimeout 100 $ do
setCompletions $ const []
onFocus (_ /\ setCompletions) e = setCompletions $ const $ autocompleteSearch state'
onInput (_ /\ setCompletions) e = do
let val = R2.unsafeEventValue e
setState $ const val
setCompletions $ const $ autocompleteSearch val
onInputKeyUp :: R.Ref (Nullable DOM.Element) -> R.State Completions -> DE.KeyboardEvent -> Effect Unit
onInputKeyUp inputRef (_ /\ setCompletions) e = do
if DE.key e == "Enter" then do
let val = R2.unsafeEventValue e
let mInput = toMaybe $ R.readRef inputRef
setState $ const val
onEnterPress val
case mInput of
Nothing -> pure unit
Just input -> R2.blur input
else
pure $ unit
completionsCpt :: R.State Completions -> R.Element
completionsCpt (completions /\ setCompletions) =
H.div { className }
[
H.div { className: "list-group" } (cCpt <$> completions)
]
where
className = "completions " <> (if completions == [] then "hidden" else "")
cCpt c =
H.button { type: "button"
, className: "list-group-item"
, on: { click: onClick c } } [ H.text c ]
onClick c _ = do
setState $ const c
onAutocompleteClick c
module Gargantext.Components.Search.SearchField module Gargantext.Components.Search.SearchField
( Search, Props, defaultSearch, searchField, searchFieldComponent, isIsTex) where ( Search, Props, defaultSearch, searchField, searchFieldComponent, isIsTex) where
import Prelude (const, map, pure, show, discard, ($), (&&), (<), (<$>), (<>), (==)) import Prelude (const, map, pure, show, discard, ($), (&&), (<), (<$>), (<>), (==), (<<<))
import Data.Maybe (Maybe(..), maybe) import Data.Maybe (Maybe(..), maybe)
import Data.String (length) import Data.String (length)
import Data.Set as Set import Data.Set as Set
...@@ -9,7 +9,6 @@ import Data.Tuple (fst) ...@@ -9,7 +9,6 @@ import Data.Tuple (fst)
import Data.Tuple.Nested ((/\)) import Data.Tuple.Nested ((/\))
import DOM.Simple.Console (log2) import DOM.Simple.Console (log2)
import Gargantext.Utils.Reactix as R2 import Gargantext.Utils.Reactix as R2
import FFI.Simple ((..))
import Reactix as R import Reactix as R
import Reactix.DOM.HTML as H import Reactix.DOM.HTML as H
import Gargantext.Components.Search.Types -- (Database(..), readDatabase, Lang(..), readLang, Org(..), readOrg, allOrgs, allIMTorgs, HAL_Filters(..), IMT_org(..)) import Gargantext.Components.Search.Types -- (Database(..), readDatabase, Lang(..), readLang, Org(..), readOrg, allOrgs, allIMTorgs, HAL_Filters(..), IMT_org(..))
...@@ -185,7 +184,7 @@ langList (lang /\ setLang) langs = ...@@ -185,7 +184,7 @@ langList (lang /\ setLang) langs =
liItem :: Lang -> R.Element liItem :: Lang -> R.Element
liItem l = H.option {className : "text-primary center"} [ H.text (show l) ] liItem l = H.option {className : "text-primary center"} [ H.text (show l) ]
lang' e = readLang $ e .. "target" .. "value" lang' = readLang <<< R2.unsafeEventValue
langNav :: R.State Search -> Array Lang -> R.Element langNav :: R.State Search -> Array Lang -> R.Element
...@@ -260,7 +259,7 @@ databaseInput ({datafield} /\ setSearch) dbs = ...@@ -260,7 +259,7 @@ databaseInput ({datafield} /\ setSearch) dbs =
liItem db' = H.option {className : "text-primary center"} [ H.text (show db') ] liItem db' = H.option {className : "text-primary center"} [ H.text (show db') ]
onChange e = do onChange e = do
let value = e .. "target" .. "value" let value = R2.unsafeEventValue e
setSearch $ _ {datafield = Just $ External $ readDatabase value } setSearch $ _ {datafield = Just $ External $ readDatabase value }
...@@ -276,7 +275,7 @@ orgInput ({datafield} /\ setSearch) orgs = ...@@ -276,7 +275,7 @@ orgInput ({datafield} /\ setSearch) orgs =
liItem :: Org -> R.Element liItem :: Org -> R.Element
liItem org = H.option {className : "text-primary center"} [ H.text (show org) ] liItem org = H.option {className : "text-primary center"} [ H.text (show org) ]
onChange e = do onChange e = do
let value = e .. "target" .. "value" let value = R2.unsafeEventValue e
setSearch $ _ { datafield = Just $ External $ Just $ HAL $ readOrg value } setSearch $ _ { datafield = Just $ External $ Just $ HAL $ readOrg value }
filterInput :: R.State String -> R.Element filterInput :: R.State String -> R.Element
...@@ -284,10 +283,7 @@ filterInput (term /\ setTerm) = ...@@ -284,10 +283,7 @@ filterInput (term /\ setTerm) =
H.div {className: "form-group"} [ H.input { defaultValue: term H.div {className: "form-group"} [ H.input { defaultValue: term
, className: "form-control" , className: "form-control"
, type: "text" , type: "text"
, on: { change: \e -> setTerm , on: { change: setTerm <<< const <<< R2.unsafeEventValue }
$ const
$ e .. "target" .. "value"
}
, "required pattern": "[[0-9]+[ ]+]*" , "required pattern": "[[0-9]+[ ]+]*"
-- TODO ^FIXME not sure about the regex comprehension: that should match "123 2334 44545" only (Integers separated by one space) -- TODO ^FIXME not sure about the regex comprehension: that should match "123 2334 44545" only (Integers separated by one space)
-- form validation with CSS -- form validation with CSS
...@@ -308,8 +304,7 @@ searchInput ({term} /\ setSearch) = ...@@ -308,8 +304,7 @@ searchInput ({term} /\ setSearch) =
] ]
where where
onChange e = do onChange e = do
let value = e .. "target" .. "value" setSearch $ _ { term = R2.unsafeEventValue e }
setSearch $ _ {term = value }
submitButton :: R.State Search submitButton :: R.State Search
......
...@@ -132,12 +132,6 @@ handleForceAtlas2Pause sigmaRef (toggled /\ setToggled) mFAPauseRef = do ...@@ -132,12 +132,6 @@ handleForceAtlas2Pause sigmaRef (toggled /\ setToggled) mFAPauseRef = do
-- restore edges state -- restore edges state
Sigma.stopForceAtlas2 s Sigma.stopForceAtlas2 s
_ -> pure unit _ -> pure unit
-- handle case when user pressed pause/start fa button before timeout fired
--case R.readRef mFAPauseRef of
-- Nothing -> pure unit
-- Just timeoutId -> do
-- R.setRef mFAPauseRef Nothing
-- clearTimeout timeoutId
setEdges :: Sigma.Sigma -> Boolean -> Effect Unit setEdges :: Sigma.Sigma -> Boolean -> Effect Unit
setEdges sigma val = do setEdges sigma val = do
...@@ -148,45 +142,6 @@ setEdges sigma val = do ...@@ -148,45 +142,6 @@ setEdges sigma val = do
} }
Sigma.setSettings sigma settings Sigma.setSettings sigma settings
-- -- prevent showing edges (via show edges button) when FA is running (flickering)
-- isFARunning <- Sigma.isForceAtlas2Running sigma
-- case Tuple val isFARunning of
-- Tuple false _ ->
-- Sigma.setSettings sigma settings
-- Tuple true false ->
-- Sigma.setSettings sigma settings
-- _ -> pure unit
markSelectedEdges :: Sigma.Sigma -> ST.SelectedEdgeIds -> ST.EdgesMap -> Effect Unit
markSelectedEdges sigma selectedEdgeIds graphEdges = do
Sigma.forEachEdge sigma \e -> do
case Map.lookup e.id graphEdges of
Nothing -> error $ "Edge id " <> e.id <> " not found in graphEdges map"
Just {color} -> do
let newColor =
if Set.member e.id selectedEdgeIds then
"#ff0000"
else
color
_ <- pure $ (e .= "color") newColor
pure unit
Sigma.refresh sigma
markSelectedNodes :: Sigma.Sigma -> ST.SelectedNodeIds -> ST.NodesMap -> Effect Unit
markSelectedNodes sigma selectedNodeIds graphNodes = do
Sigma.forEachNode sigma \n -> do
case Map.lookup n.id graphNodes of
Nothing -> error $ "Node id " <> n.id <> " not found in graphNodes map"
Just {color} -> do
let newColor =
if Set.member n.id selectedNodeIds then
"#ff0000"
else
color
_ <- pure $ (n .= "color") newColor
pure unit
Sigma.refresh sigma
updateEdges :: Sigma.Sigma -> ST.EdgesMap -> Effect Unit updateEdges :: Sigma.Sigma -> ST.EdgesMap -> Effect Unit
updateEdges sigma edgesMap = do updateEdges sigma edgesMap = do
...@@ -207,9 +162,14 @@ updateNodes sigma nodesMap = do ...@@ -207,9 +162,14 @@ updateNodes sigma nodesMap = do
let mTNode = Map.lookup n.id nodesMap let mTNode = Map.lookup n.id nodesMap
case mTNode of case mTNode of
Nothing -> error $ "Node id " <> n.id <> " not found in nodesMap" Nothing -> error $ "Node id " <> n.id <> " not found in nodesMap"
(Just {color: tColor, hidden: tHidden}) -> do (Just { borderColor: tBorderColor
, color: tColor
, hidden: tHidden
, type: tType}) -> do
_ <- pure $ (n .= "borderColor") tBorderColor
_ <- pure $ (n .= "color") tColor _ <- pure $ (n .= "color") tColor
_ <- pure $ (n .= "hidden") tHidden _ <- pure $ (n .= "hidden") tHidden
_ <- pure $ (n .= "type") tType
pure unit pure unit
--Sigma.refresh sigma --Sigma.refresh sigma
...@@ -244,3 +204,39 @@ bindSelectedEdgesClick sigmaRef (_ /\ setSelectedEdgeIds) = ...@@ -244,3 +204,39 @@ bindSelectedEdgesClick sigmaRef (_ /\ setSelectedEdgeIds) =
Set.delete edge.id eids Set.delete edge.id eids
else else
Set.insert edge.id eids Set.insert edge.id eids
selectorWithSize :: Sigma.Sigma -> Int -> Effect Unit
selectorWithSize sigma size = do
pure unit
-- DEPRECATED
markSelectedEdges :: Sigma.Sigma -> ST.SelectedEdgeIds -> ST.EdgesMap -> Effect Unit
markSelectedEdges sigma selectedEdgeIds graphEdges = do
Sigma.forEachEdge sigma \e -> do
case Map.lookup e.id graphEdges of
Nothing -> error $ "Edge id " <> e.id <> " not found in graphEdges map"
Just {color} -> do
let newColor =
if Set.member e.id selectedEdgeIds then
"#ff0000"
else
color
_ <- pure $ (e .= "color") newColor
pure unit
Sigma.refresh sigma
markSelectedNodes :: Sigma.Sigma -> ST.SelectedNodeIds -> ST.NodesMap -> Effect Unit
markSelectedNodes sigma selectedNodeIds graphNodes = do
Sigma.forEachNode sigma \n -> do
case Map.lookup n.id graphNodes of
Nothing -> error $ "Node id " <> n.id <> " not found in graphNodes map"
Just {color} -> do
let newColor =
if Set.member n.id selectedNodeIds then
"#ff0000"
else
color
_ <- pure $ (n .= "color") newColor
pure unit
Sigma.refresh sigma
...@@ -6,7 +6,21 @@ if (typeof window !== 'undefined') { ...@@ -6,7 +6,21 @@ if (typeof window !== 'undefined') {
window.sigma = sigma; window.sigma = sigma;
} }
require('sigma/plugins/garg.js').init(sigma, window); const CustomShapes = require('sigma/plugins/garg.js').init(sigma, window).customShapes;
require('sigma/src/utils/sigma.utils.js').init(sigma);
sigma.canvas.nodes.hovered = (node, context, settings) => {
// hack
// We need to temporarily set node.type to 'def'. This is for 2 reasons
// 1. Make it render as a normal node
// 2. Avoid infinite recursion (hovers.def calls node renderer and we would end up here back
// again with node.type = 'hovered')
node.type = 'def';
sigma.canvas.hovers.def(node, context, settings);
node.type = 'hovered';
};
CustomShapes.init();
function _sigma(left, right, opts) { function _sigma(left, right, opts) {
try { try {
......
...@@ -22,18 +22,21 @@ type Renderer = { "type" :: String, container :: Element } ...@@ -22,18 +22,21 @@ type Renderer = { "type" :: String, container :: Element }
type Node = type Node =
( id :: String ( borderColor :: String
, label :: String , color :: String
, hidden :: Boolean , hidden :: Boolean
, id :: String
, label :: String
, size :: Number
, type :: String -- available types: circle, cross, def, diamond, equilateral, pacman, square, star
, x :: Number , x :: Number
, y :: Number , y :: Number
, size :: Number )
, color :: String )
type Edge = type Edge =
( id :: String ( color :: String
, color :: String
, confluence :: Number , confluence :: Number
, id :: String
, hidden :: Boolean , hidden :: Boolean
, size :: Number , size :: Number
, source :: String , source :: String
......
...@@ -223,3 +223,6 @@ inputFileBlob e = unsafePartial $ do ...@@ -223,3 +223,6 @@ inputFileBlob e = unsafePartial $ do
dataTransferFileBlob e = unsafePartial $ do dataTransferFileBlob e = unsafePartial $ do
let ff = fromJust $ item 0 $ ((e .. "dataTransfer" .. "files") :: FileList) let ff = fromJust $ item 0 $ ((e .. "dataTransfer" .. "files") :: FileList)
pure $ toBlob ff pure $ toBlob ff
blur :: DOM.Element -> Effect Unit
blur el = el ... "blur" $ []
...@@ -5613,10 +5613,10 @@ sander@^0.5.0: ...@@ -5613,10 +5613,10 @@ sander@^0.5.0:
mkdirp "^0.5.1" mkdirp "^0.5.1"
rimraf "^2.5.2" rimraf "^2.5.2"
sass@^1.22.9: sass@^1.23.7:
version "1.22.9" version "1.23.7"
resolved "https://registry.yarnpkg.com/sass/-/sass-1.22.9.tgz#41a2ed6038027f58be2bd5041293452a29c2cb84" resolved "https://registry.yarnpkg.com/sass/-/sass-1.23.7.tgz#090254e006af1219d442f1bff31e139d5e085dff"
integrity sha512-FzU1X2V8DlnqabrL4u7OBwD2vcOzNMongEJEx3xMEhWY/v26FFR3aG0hyeu2T965sfR0E9ufJwmG+Qjz78vFPQ== integrity sha512-cYgc0fanwIpi0rXisGxl+/wadVQ/HX3RhpdRcjLdj2o2ye/sxUTpAxIhbmJy3PLQgRFbf6Pn8Jsrta2vdXcoOQ==
dependencies: dependencies:
chokidar ">=2.0.0 <4.0.0" chokidar ">=2.0.0 <4.0.0"
......
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