Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
P
purescript-gargantext
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
142
Issues
142
List
Board
Labels
Milestones
Merge Requests
4
Merge Requests
4
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
gargantext
purescript-gargantext
Commits
1b753ff9
Commit
1b753ff9
authored
Mar 05, 2021
by
Przemyslaw Kaminski
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[toestand] more refactoring work
parent
7d5673d3
Changes
31
Hide whitespace changes
Inline
Side-by-side
Showing
31 changed files
with
850 additions
and
532 deletions
+850
-532
Forest.purs
src/Gargantext/Components/Forest.purs
+2
-4
Tree.purs
src/Gargantext/Components/Forest/Tree.purs
+4
-4
Node.purs
src/Gargantext/Components/Forest/Tree/Node.purs
+2
-2
Contact.purs
...argantext/Components/Forest/Tree/Node/Action/Contact.purs
+3
-2
Box.purs
src/Gargantext/Components/Forest/Tree/Node/Box.purs
+2
-2
Tools.purs
src/Gargantext/Components/Forest/Tree/Node/Tools.purs
+4
-3
Graph.purs
src/Gargantext/Components/Graph.purs
+64
-32
GraphExplorer.purs
src/Gargantext/Components/GraphExplorer.purs
+63
-34
Controls.purs
src/Gargantext/Components/GraphExplorer/Controls.purs
+84
-63
RangeControl.purs
src/Gargantext/Components/GraphExplorer/RangeControl.purs
+88
-46
Search.purs
src/Gargantext/Components/GraphExplorer/Search.purs
+18
-14
Sidebar.purs
src/Gargantext/Components/GraphExplorer/Sidebar.purs
+209
-117
SlideButton.purs
src/Gargantext/Components/GraphExplorer/SlideButton.purs
+13
-12
ToggleButton.purs
src/Gargantext/Components/GraphExplorer/ToggleButton.purs
+132
-76
Login.purs
src/Gargantext/Components/Login.purs
+2
-1
Document.purs
src/Gargantext/Components/Nodes/Corpus/Document.purs
+9
-9
Types.purs
src/Gargantext/Components/Nodes/Corpus/Document/Types.purs
+6
-6
Texts.purs
src/Gargantext/Components/Nodes/Texts.purs
+53
-38
RangeSlider.purs
src/Gargantext/Components/RangeSlider.purs
+2
-0
Router.purs
src/Gargantext/Components/Router.purs
+48
-43
Search.purs
src/Gargantext/Components/Search.purs
+1
-0
Tab.purs
src/Gargantext/Components/Tab.purs
+2
-2
Table.purs
src/Gargantext/Components/Table.purs
+2
-2
TopBar.purs
src/Gargantext/Components/TopBar.purs
+2
-1
Hooks.purs
src/Gargantext/Hooks.purs
+3
-1
Sigmax.purs
src/Gargantext/Hooks/Sigmax.purs
+9
-6
Sessions.purs
src/Gargantext/Sessions.purs
+2
-2
Range.purs
src/Gargantext/Utils/Range.purs
+3
-0
Reload.purs
src/Gargantext/Utils/Reload.purs
+3
-3
Toestand.purs
src/Gargantext/Utils/Toestand.purs
+10
-3
Spec.purs
test/Gargantext/Utils/Spec.purs
+5
-4
No files found.
src/Gargantext/Components/Forest.purs
View file @
1b753ff9
...
...
@@ -76,8 +76,7 @@ forestCpt = here.component "forest" cpt where
-- NOTE: this is a hack to reload the forest on demand
tasks' <- GAT.useTasks reloadRoot reloadForest
R.useEffect' $ do
_ <- T.write (Just tasks') tasks
pure unit
T2.write_ (Just tasks') tasks
handed' <- T.useLive T.unequal handed
reloadForest' <- T.useLive T.unequal reloadForest
reloadRoot' <- T.useLive T.unequal reloadRoot
...
...
@@ -124,8 +123,7 @@ plus handed showLogin backend = H.div { className: "row" }
where
click _ = do
-- _ <- T.modify (const Nothing) backend
_ <- T.write true showLogin
pure unit
T2.write_ true showLogin
title = "Add or remove connections to the server(s)."
divClass = "fa fa-universal-access"
buttonClass =
...
...
src/Gargantext/Components/Forest/Tree.purs
View file @
1b753ff9
...
...
@@ -172,7 +172,7 @@ performAction (DeleteNode nt) p@{ forestOpen
GT.NodePublic GT.FolderPublic -> void $ deleteNode session nt id
GT.NodePublic _ -> void $ unpublishNode session parent_id id
_ -> void $ deleteNode session nt id
_ <- liftEffect $ T.modify
(Set.delete (mkNodeId session id)) forestOpen
liftEffect $ T2.modify_
(Set.delete (mkNodeId session id)) forestOpen
performAction RefreshTree p
performAction (DoSearch task) p@{ tasks
, tree: (NTree (LNode {id}) _) } = liftEffect $ do
...
...
@@ -198,14 +198,14 @@ performAction (ShareTeam username) p@{ tree: (NTree (LNode {id}) _)} =
performAction (SharePublic { params }) p@{ forestOpen } = traverse_ f params where
f (SubTreeOut { in: inId, out }) = do
void $ Share.shareReq p.session inId $ Share.SharePublicParams { node_id: out }
_ <- liftEffect $ T.modify
(Set.insert (mkNodeId p.session out)) forestOpen
liftEffect $ T2.modify_
(Set.insert (mkNodeId p.session out)) forestOpen
performAction RefreshTree p
performAction (AddContact params) p@{ tree: (NTree (LNode {id}) _) } =
void $ Contact.contactReq p.session id params
performAction (AddNode name nodeType) p@{ forestOpen
, tree: (NTree (LNode { id }) _) } = do
task <- addNode p.session id $ AddNodeValue {name, nodeType}
_ <- liftEffect $ T.modify
(Set.insert (mkNodeId p.session id)) forestOpen
liftEffect $ T2.modify_
(Set.insert (mkNodeId p.session id)) forestOpen
performAction RefreshTree p
performAction (UploadFile nodeType fileType mName blob) p@{ tasks
, tree: (NTree (LNode { id }) _) } = do
...
...
@@ -230,7 +230,7 @@ performAction (MoveNode {params}) p@{ forestOpen
, session } = traverse_ f params where
f (SubTreeOut { in: in', out }) = do
void $ moveNodeReq p.session in' out
_ <- liftEffect $ T.modify
(Set.insert (mkNodeId session out)) forestOpen
liftEffect $ T2.modify_
(Set.insert (mkNodeId session out)) forestOpen
performAction RefreshTree p
performAction (MergeNode { params }) p = traverse_ f params where
f (SubTreeOut { in: in', out }) = do
...
...
src/Gargantext/Components/Forest/Tree/Node.purs
View file @
1b753ff9
...
...
@@ -210,7 +210,7 @@ folderIconCpt = here.component "folderIcon" cpt
where
cpt { folderOpen, nodeType } _ = do
open <- T.read folderOpen
pure $ H.a { className: "folder-icon", on: { click: \_ -> T
.modify
not folderOpen } }
pure $ H.a { className: "folder-icon", on: { click: \_ -> T
2.modify_
not folderOpen } }
[ H.i { className: GT.fldr nodeType open } [] ]
type ChevronIconProps = (
...
...
@@ -231,7 +231,7 @@ chevronIconCpt = here.component "chevronIcon" cpt
cpt { folderOpen, handed, isLeaf: false, nodeType } _ = do
open <- T.read folderOpen
pure $ H.a { className: "chevron-icon"
, on: { click: \_ -> T
.modify
not folderOpen }
, on: { click: \_ -> T
2.modify_
not folderOpen }
}
[ H.i { className: if open
then "fa fa-chevron-down"
...
...
src/Gargantext/Components/Forest/Tree/Node/Action/Contact.purs
View file @
1b753ff9
...
...
@@ -19,6 +19,7 @@ import Gargantext.Sessions (Session, post)
import Gargantext.Types (ID)
import Gargantext.Types as GT
import Gargantext.Utils.Reactix as R2
import Gargantext.Utils.Toestand as T2
here :: R2.Here
here = R2.here "Gargantext.Components.Forest.Tree.Node.Action.Contact"
...
...
@@ -69,7 +70,7 @@ textInputBoxCpt = here.component "textInputBox" cpt where
click _ = do
firstname <- T.read first
lastname <- T.read last
_ <- T.write
false isOpen
T2.write_
false isOpen
launchAff $
dispatch (boxAction $ AddContactParams { firstname, lastname })
cancelBtn =
...
...
@@ -77,4 +78,4 @@ textInputBoxCpt = here.component "textInputBox" cpt where
{ className: "btn text-danger glyphitem fa fa-remove col-md-2 pull-left"
, on: { click }, title: "Cancel", type: "button"
} [] where
click _ =
void $ T.write
false isOpen
click _ =
T2.write_
false isOpen
src/Gargantext/Components/Forest/Tree/Node/Box.purs
View file @
1b753ff9
...
...
@@ -81,7 +81,7 @@ nodePopupCpt = here.component "nodePopupView" cpt where
editIcon _ true = H.div {} []
editIcon isOpen false =
H.a { className: glyphicon "pencil", id: "rename1"
, title : "Rename", on: { click: \_ ->
void $ T.write
true isOpen } } []
, title : "Rename", on: { click: \_ ->
T2.write_
true isOpen } } []
panelBody :: T.Cursor (Maybe NodeAction) -> Record NodePopupProps -> R.Element
panelBody nodePopupState {dispatch: d, nodeType} =
let (SettingsBox { edit, doc, buttons }) = settingsBox nodeType in
...
...
@@ -134,7 +134,7 @@ buttonClickCpt = here.component "buttonClick" cpt where
action <- T.useLive T.unequal state
let className = glyphiconActive (glyphiconNodeAction todo) (action == (Just todo))
let style = iconAStyle nodeType todo
let click _ = T
.write
(if action == Just todo then Nothing else Just todo) state
let click _ = T
2.write_
(if action == Just todo then Nothing else Just todo) state
pure $ H.div { className: "col-1" }
[ H.a { style, className, id: show todo, title: show todo, on: { click } } [] ]
-- | Open the help indications if selected already
...
...
src/Gargantext/Components/Forest/Tree/Node/Tools.purs
View file @
1b753ff9
...
...
@@ -26,6 +26,7 @@ import Gargantext.Types as GT
import Gargantext.Utils (glyphicon, toggleSet)
import Gargantext.Utils.Reactix as R2
import Gargantext.Utils.ReactTooltip as ReactTooltip
import Gargantext.Utils.Toestand as T2
here :: R2.Here
here = R2.here "Gargantext.Components.Forest.Tree.Node.Tools"
...
...
@@ -81,8 +82,8 @@ textInputBoxCpt = here.component "textInputBox" cpt where
, className: "text-danger col-2 " <> glyphicon "times" } [] ]
submit ref _ = do
launchAff_ $ dispatch (boxAction $ R.readRef ref)
void $ T.write
false isOpen
click _ =
void $ T.write
false isOpen
T2.write_
false isOpen
click _ =
T2.write_
false isOpen
type DefaultText = String
...
...
@@ -223,7 +224,7 @@ nodeLinkCpt = here.component "nodeLink" cpt where
-- NOTE Don't toggle tree if it is not selected
-- click on closed -> open
-- click on open -> ?
click _ = when (not isSelected) (
void $ T.write
true folderOpen)
click _ = when (not isSelected) (
T2.write_
true folderOpen)
tooltipId = "node-link-" <> show id
href = url frontends $ GT.NodePath (sessionId session) nodeType (Just id)
...
...
src/Gargantext/Components/Graph.purs
View file @
1b753ff9
...
...
@@ -4,17 +4,20 @@ module Gargantext.Components.Graph
-- , forceAtlas2Settings, ForceAtlas2Settings, ForceAtlas2OptionalSettings
-- )
where
import Prelude (bind, const, discard, not, pure, unit, ($))
import Data.Either (Either(..))
import Data.Generic.Rep (class Generic)
import Data.Maybe (Maybe(..))
import Data.Nullable (Nullable)
import Data.Tuple.Nested ((/\))
import DOM.Simple.Console (log, log2)
import DOM.Simple.Types (Element)
import FFI.Simple (delay)
import Reactix as R
import Reactix.DOM.HTML as RH
import Record as Record
import Toestand as T
import Gargantext.Prelude
import Gargantext.Components.GraphExplorer.Types as GET
import Gargantext.Hooks.Sigmax as Sigmax
...
...
@@ -22,40 +25,58 @@ import Gargantext.Hooks.Sigmax.Types as SigmaxTypes
import Gargantext.Hooks.Sigmax.Sigma as Sigma
import Gargantext.Utils.Reactix as R2
here :: R2.Here
here = R2.here "Gargantext.Components.Graph"
type OnProps = ()
data Stage = Init | Ready | Cleanup
derive instance genericStage :: Generic Stage _
derive instance eqStage :: Eq Stage
type Props sigma forceatlas2 = (
elRef :: R.Ref (Nullable Element)
, forceAtlas2Settings :: forceatlas2
, graph :: SigmaxTypes.SGraph
, mCamera :: Maybe GET.Camera
elRef
:: R.Ref (Nullable Element)
, forceAtlas2Settings
:: forceatlas2
, graph
:: SigmaxTypes.SGraph
, mCamera
:: Maybe GET.Camera
, multiSelectEnabledRef :: R.Ref Boolean
, selectedNodeIds
:: R.State
SigmaxTypes.NodeIds
, showEdges
:: R.State
SigmaxTypes.ShowEdgesState
, sigmaRef :: R.Ref Sigmax.Sigma
, sigmaSettings :: sigma
, stage
:: R.State
Stage
, startForceAtlas :: Boolean
, transformedGraph :: SigmaxTypes.SGraph
, selectedNodeIds
:: T.Cursor
SigmaxTypes.NodeIds
, showEdges
:: T.Cursor
SigmaxTypes.ShowEdgesState
, sigmaRef
:: R.Ref Sigmax.Sigma
, sigmaSettings
:: sigma
, stage
:: T.Cursor
Stage
, startForceAtlas
:: Boolean
, transformedGraph
:: SigmaxTypes.SGraph
)
graph :: forall s fa2. R
ecord (Props s fa2) -> R.Element
graph
props = R.createElement graphCpt props []
graph :: forall s fa2. R
2.Component (Props s fa2)
graph
= R.createElement graphCpt
graphCpt :: forall s fa2. R.Component (Props s fa2)
graphCpt = here.component "graph" cpt
where
cpt props _ = do
stageHooks props
cpt props@{ elRef
, forceAtlas2Settings
, graph
, mCamera
, multiSelectEnabledRef
, selectedNodeIds
, showEdges
, sigmaRef
, sigmaSettings
, stage
, startForceAtlas
, transformedGraph } _ = do
showEdges' <- T.useLive T.unequal showEdges
stage' <- T.useLive T.unequal stage
stageHooks (Record.merge { showEdges', stage' } props)
R.useEffectOnce $ do
pure $ do
log "[graphCpt (Cleanup)]"
Sigmax.dependOnSigma (R.readRef
props.
sigmaRef) "[graphCpt (Cleanup)] no sigma" $ \sigma -> do
Sigmax.dependOnSigma (R.readRef sigmaRef) "[graphCpt (Cleanup)] no sigma" $ \sigma -> do
Sigma.stopForceAtlas2 sigma
log2 "[graphCpt (Cleanup)] forceAtlas stopped for" sigma
Sigma.kill sigma
...
...
@@ -63,24 +84,32 @@ graphCpt = here.component "graph" cpt
-- NOTE: This div is not empty after sigma initializes.
-- When we change state, we make it empty though.
--pure $ RH.div { ref:
props.
elRef, style: {height: "95%"} } []
pure $ case R.readNullableRef
props.
elRef of
--pure $ RH.div { ref: elRef, style: {height: "95%"} } []
pure $ case R.readNullableRef elRef of
Nothing -> RH.div {} []
Just el -> R.createPortal [] el
stageHooks props@{multiSelectEnabledRef, selectedNodeIds, sigmaRef, stage: (Init /\ setStage)} = do
stageHooks { elRef
, graph
, mCamera
, multiSelectEnabledRef
, selectedNodeIds
, sigmaRef
, stage
, stage': Init
, startForceAtlas } = do
R.useEffectOnce' $ do
let rSigma = R.readRef
props.
sigmaRef
let rSigma = R.readRef sigmaRef
case Sigmax.readSigma rSigma of
Nothing -> do
eSigma <- Sigma.sigma {settings:
props.
sigmaSettings}
eSigma <- Sigma.sigma {settings: sigmaSettings}
case eSigma of
Left err -> log2 "[graphCpt] error creating sigma" err
Right sig -> do
Sigmax.writeSigma rSigma $ Just sig
Sigmax.dependOnContainer
props.
elRef "[graphCpt (Ready)] container not found" $ \c -> do
Sigmax.dependOnContainer elRef "[graphCpt (Ready)] container not found" $ \c -> do
_ <- Sigma.addRenderer sig {
"type": "canvas"
, container: c
...
...
@@ -88,7 +117,7 @@ graphCpt = here.component "graph" cpt
}
pure unit
Sigmax.refreshData sig $ Sigmax.sigmafy
props.
graph
Sigmax.refreshData sig $ Sigmax.sigmafy graph
Sigmax.dependOnSigma (R.readRef sigmaRef) "[graphCpt (Ready)] no sigma" $ \sigma -> do
-- bind the click event only initially, when ref was empty
...
...
@@ -98,13 +127,13 @@ graphCpt = here.component "graph" cpt
Sigmax.setEdges sig false
-- log2 "[graph] startForceAtlas"
props.
startForceAtlas
if
props.
startForceAtlas then
Sigma.startForceAtlas2 sig
props.
forceAtlas2Settings
-- log2 "[graph] startForceAtlas" startForceAtlas
if startForceAtlas then
Sigma.startForceAtlas2 sig forceAtlas2Settings
else
Sigma.stopForceAtlas2 sig
case
props.
mCamera of
case mCamera of
Nothing -> pure unit
Just (GET.Camera { ratio, x, y }) -> do
Sigma.updateCamera sig { ratio, x, y }
...
...
@@ -113,9 +142,12 @@ graphCpt = here.component "graph" cpt
Just sig -> do
pure unit
setStage $ const Ready
T.write Ready stage
stageHooks props@{ showEdges: (showEdges /\ _), sigmaRef, stage: (Ready /\ setStage), transformedGraph } = do
stageHooks { showEdges'
, sigmaRef
, stage': Ready
, transformedGraph } = do
let tEdgesMap = SigmaxTypes.edgesGraphMap transformedGraph
let tNodesMap = SigmaxTypes.nodesGraphMap transformedGraph
...
...
@@ -125,7 +157,7 @@ graphCpt = here.component "graph" cpt
Sigmax.performDiff sigma transformedGraph
Sigmax.updateEdges sigma tEdgesMap
Sigmax.updateNodes sigma tNodesMap
Sigmax.setEdges sigma (not $ SigmaxTypes.edgeStateHidden showEdges)
Sigmax.setEdges sigma (not $ SigmaxTypes.edgeStateHidden showEdges
'
)
stageHooks _ = pure unit
...
...
src/Gargantext/Components/GraphExplorer.purs
View file @
1b753ff9
...
...
@@ -11,7 +11,7 @@ import Data.Maybe (Maybe(..), fromJust, maybe)
import Data.Nullable (null, Nullable)
import Data.Sequence as Seq
import Data.Set as Set
import Data.Tuple (
fst, snd,
Tuple(..))
import Data.Tuple (Tuple(..))
import Data.Tuple.Nested ((/\))
import Effect.Aff (Aff)
import Math (log)
...
...
@@ -126,10 +126,12 @@ explorerCpt = here.component "explorer" cpt
, graph
, graphId
, hyperdataGraph
, session
, reloadForest: \_ -> GUR.bumpCursor reloadForest
, session
}
multiSelectEnabledRef <- R.useRef $ fst controls.multiSelectEnabled
multiSelectEnabled' <- T.useLive T.unequal controls.multiSelectEnabled
showTree' <- T.useLive T.unequal controls.showTree
multiSelectEnabledRef <- R.useRef multiSelectEnabled'
forestOpen <- T2.useCursed $ Set.empty
...
...
@@ -145,21 +147,21 @@ explorerCpt = here.component "explorer" cpt
R.setRef dataRef graph
R.setRef graphVersionRef (GUR.value graphVersion)
-- Reinitialize bunch of state as well.
snd controls.removedNodeIds $ const SigmaxT.empty
NodeIds
snd controls.selectedNodeIds $ const SigmaxT.empty
NodeIds
snd controls.showEdges $ const SigmaxT.EShow
snd controls.forceAtlasState $ const forceAtlasS
snd controls.graphStage $ const Graph.Init
snd controls.showSidePanel $ const GET.InitialClosed
T2.write_ SigmaxT.emptyNodeIds controls.removed
NodeIds
T2.write_ SigmaxT.emptyNodeIds controls.selected
NodeIds
T2.write_ SigmaxT.EShow controls.showEdges
T2.write_ forceAtlasS controls.forceAtlasState
T2.write_ Graph.Init controls.graphStage
T2.write_ GET.InitialClosed controls.showSidePanel
pure $
RH.div { className: "graph-meta-container" } [
RH.div { className: "fixed-top navbar navbar-expand-lg"
, id: "graph-explorer" }
[ rowToggle
[ col [ spaces [ Toggle.treeToggleButton
controls.showTree
]]
, col [ spaces [ Toggle.controlsToggleButton
controls.showControls
]]
, col [ spaces [ Toggle.sidebarToggleButton
controls.showSidePanel
]]
[ col [ spaces [ Toggle.treeToggleButton
{ state: controls.showTree } []
]]
, col [ spaces [ Toggle.controlsToggleButton
{ state: controls.showControls } []
]]
, col [ spaces [ Toggle.sidebarToggleButton
{ state: controls.showSidePanel } []
]]
]
]
, RH.div { className: "graph-container" } [
...
...
@@ -174,7 +176,7 @@ explorerCpt = here.component "explorer" cpt
, route
, reloadForest
, sessions
, show:
fst controls.showTree
, show:
showTree'
, showLogin: showLogin
, tasks
}
...
...
@@ -267,10 +269,10 @@ type MSidebarProps =
, graphId :: GET.GraphId
, graphVersion :: GUR.ReloadS
, reloadForest :: T.Cursor T2.Reload
, removedNodeIds ::
R.State
SigmaxT.NodeIds
, selectedNodeIds ::
R.State
SigmaxT.NodeIds
, removedNodeIds ::
T.Cursor
SigmaxT.NodeIds
, selectedNodeIds ::
T.Cursor
SigmaxT.NodeIds
, session :: Session
, showSidePanel ::
R.State
GET.SidePanelState
, showSidePanel ::
T.Cursor
GET.SidePanelState
)
type GraphProps = (
...
...
@@ -297,19 +299,33 @@ graphViewCpt = here.component "graphView" cpt
, hyperdataGraph: GET.HyperdataGraph { mCamera }
, mMetaData
, multiSelectEnabledRef } _children = do
edgeConfluence' <- T.useLive T.unequal controls.edgeConfluence
edgeWeight' <- T.useLive T.unequal controls.edgeWeight
multiSelectEnabled' <- T.useLive T.unequal controls.multiSelectEnabled
nodeSize' <- T.useLive T.unequal controls.nodeSize
removedNodeIds' <- T.useLive T.unequal controls.removedNodeIds
selectedNodeIds' <- T.useLive T.unequal controls.selectedNodeIds
showEdges' <- T.useLive T.unequal controls.showEdges
showLouvain' <- T.useLive T.unequal controls.showLouvain
-- TODO Cache this?
let louvainGraph =
if
(fst controls.showLouvain)
then
if
showLouvain'
then
let louvain = Louvain.louvain unit in
let cluster = Louvain.init louvain (SigmaxT.louvainNodes graph) (SigmaxT.louvainEdges graph) in
SigmaxT.louvainGraph graph cluster
else
graph
let transformedGraph = transformGraph controls louvainGraph
let transformedGraph = transformGraph louvainGraph { edgeConfluence'
, edgeWeight'
, nodeSize'
, removedNodeIds'
, selectedNodeIds'
, showEdges' }
let startForceAtlas = maybe true (\(GET.MetaData { startForceAtlas }) -> startForceAtlas) mMetaData
R.useEffect1'
(fst controls.multiSelectEnabled)
$ do
R.setRef multiSelectEnabledRef
$ fst controls.multiSelectEnabled
R.useEffect1'
multiSelectEnabled'
$ do
R.setRef multiSelectEnabledRef
multiSelectEnabled'
pure $ Graph.graph { elRef
, forceAtlas2Settings: Graph.forceAtlas2Settings
...
...
@@ -323,7 +339,7 @@ graphViewCpt = here.component "graphView" cpt
, stage: controls.graphStage
, startForceAtlas
, transformedGraph
}
}
[]
convert :: GET.GraphData -> Tuple (Maybe GET.MetaData) SigmaxT.SGraph
convert (GET.GraphData r) = Tuple r.metaData $ SigmaxT.Graph {nodes, edges}
...
...
@@ -384,17 +400,30 @@ getNodes session graphVersion graphId =
(Just graphId)
("?version=" <> (show $ GUR.value graphVersion))
type LiveProps = (
edgeConfluence' :: Range.NumberRange
, edgeWeight' :: Range.NumberRange
, nodeSize' :: Range.NumberRange
, removedNodeIds' :: SigmaxT.NodeIds
, selectedNodeIds' :: SigmaxT.NodeIds
, showEdges' :: SigmaxT.ShowEdgesState
)
transformGraph :: Record Controls.Controls -> SigmaxT.SGraph -> SigmaxT.SGraph
transformGraph controls graph = SigmaxT.Graph {nodes: newNodes, edges: newEdges}
transformGraph :: SigmaxT.SGraph -> Record LiveProps -> SigmaxT.SGraph
transformGraph graph { edgeConfluence'
, edgeWeight'
, nodeSize'
, removedNodeIds'
, selectedNodeIds'
, showEdges' } = SigmaxT.Graph {nodes: newNodes, edges: newEdges}
where
edges = SigmaxT.graphEdges graph
nodes = SigmaxT.graphNodes graph
selectedEdgeIds =
Set.fromFoldable
$ Seq.map _.id
$ SigmaxT.neighbouringEdges graph
(fst controls.selectedNodeIds)
hasSelection = not $ Set.isEmpty
(fst controls.selectedNodeIds)
$ SigmaxT.neighbouringEdges graph
selectedNodeIds'
hasSelection = not $ Set.isEmpty
selectedNodeIds'
newEdges' = Seq.filter edgeFilter $ Seq.map (
edgeHideWeight <<< edgeHideConfluence <<< edgeShowFilter <<< edgeMarked
...
...
@@ -406,32 +435,32 @@ transformGraph controls graph = SigmaxT.Graph {nodes: newNodes, edges: newEdges}
nodeFilter n = nodeRemovedFilter n
nodeSizeFilter :: Record SigmaxT.Node -> Boolean
nodeSizeFilter node@{ size } = Range.within
(fst controls.nodeSize)
size
nodeSizeFilter node@{ size } = Range.within
nodeSize'
size
nodeRemovedFilter node@{ id } = not $ Set.member id
$ fst controls.removedNodeIds
nodeRemovedFilter node@{ id } = not $ Set.member id
removedNodeIds'
edgeConfluenceFilter :: Record SigmaxT.Edge -> Boolean
edgeConfluenceFilter edge@{ confluence } = Range.within
(fst controls.edgeConfluence)
confluence
edgeConfluenceFilter edge@{ confluence } = Range.within
edgeConfluence'
confluence
edgeWeightFilter :: Record SigmaxT.Edge -> Boolean
edgeWeightFilter edge@{ weightIdx } = Range.within
(fst controls.edgeWeight)
$ toNumber weightIdx
edgeWeightFilter edge@{ weightIdx } = Range.within
edgeWeight'
$ toNumber weightIdx
edgeHideConfluence :: Record SigmaxT.Edge -> Record SigmaxT.Edge
edgeHideConfluence edge@{ confluence } =
if Range.within
(fst controls.edgeConfluence)
confluence then
if Range.within
edgeConfluence'
confluence then
edge
else
edge { hidden = true }
edgeHideWeight :: Record SigmaxT.Edge -> Record SigmaxT.Edge
edgeHideWeight edge@{ weightIdx } =
if Range.within
(fst controls.edgeWeight)
$ toNumber weightIdx then
if Range.within
edgeWeight'
$ toNumber weightIdx then
edge
else
edge { hidden = true }
edgeShowFilter :: Record SigmaxT.Edge -> Record SigmaxT.Edge
edgeShowFilter edge =
if
(SigmaxT.edgeStateHidden $ fst controls.showEdges)
then
if
SigmaxT.edgeStateHidden showEdges'
then
edge { hidden = true }
else
edge
...
...
@@ -450,14 +479,14 @@ transformGraph controls graph = SigmaxT.Graph {nodes: newNodes, edges: newEdges}
nodeMarked :: Record SigmaxT.Node -> Record SigmaxT.Node
nodeMarked node@{ id } =
if Set.member id
(fst controls.selectedNodeIds)
then
if Set.member id
selectedNodeIds'
then
node { borderColor = "#000", type = "selected" }
else
node
nodeHideSize :: Record SigmaxT.Node -> Record SigmaxT.Node
nodeHideSize node@{ size } =
if Range.within
(fst controls.nodeSize)
size then
if Range.within
nodeSize'
size then
node
else
node { hidden = true }
src/Gargantext/Components/GraphExplorer/Controls.purs
View file @
1b753ff9
...
...
@@ -3,8 +3,8 @@ module Gargantext.Components.GraphExplorer.Controls
, useGraphControls
, controls
, controlsCpt
,
getShowTree,
setShowTree
,
getShowControls,
setShowControls
, setShowTree
, setShowControls
) where
import Data.Array as A
...
...
@@ -81,7 +81,30 @@ controls props = R.createElement controlsCpt props []
controlsCpt :: R.Component Controls
controlsCpt = here.component "controls" cpt
where
cpt props _ = do
cpt { edgeConfluence
, edgeWeight
, forceAtlasState
, graph
, graphId
, graphStage
, hyperdataGraph
, multiSelectEnabled
, nodeSize
, reloadForest
, selectedNodeIds
, session
, showControls
, showEdges
, showLouvain
, showSidePanel
, showTree
, sigmaRef } _ = do
forceAtlasState' <- T.useLive T.unequal forceAtlasState
graphStage' <- T.useLive T.unequal graphStage
selectedNodeIds' <- T.useLive T.unequal selectedNodeIds
showControls' <- T.useLive T.unequal showControls
showSidePanel' <- T.useLive T.unequal showSidePanel
localControls <- initialLocalControls
-- ref to track automatic FA pausing
-- If user pauses FA before auto is triggered, clear the timeoutId
...
...
@@ -90,32 +113,32 @@ controlsCpt = here.component "controls" cpt
-- When graph is changed, cleanup the mFAPauseRef so that forceAtlas
-- timeout is retriggered.
R.useEffect' $ do
case
fst props.graphStage
of
case
graphStage'
of
Graph.Init -> R.setRef mFAPauseRef Nothing
_ -> pure unit
-- Handle case when FA is paused from outside events, eg. the automatic timer.
R.useEffect' $ Sigmax.handleForceAtlas2Pause
props.sigmaRef props.
forceAtlasState mFAPauseRef
R.useEffect' $ Sigmax.handleForceAtlas2Pause
sigmaRef
forceAtlasState mFAPauseRef
-- Handle automatic edge hiding when FA is running (to prevent flickering).
R.useEffect2'
props.sigmaRef props.forceAtlasState $
snd props.showEdges $ SigmaxT.forceAtlasEdgeState (fst props.forceAtlasState)
R.useEffect2'
sigmaRef forceAtlasState' $ do
T2.modify_ (SigmaxT.forceAtlasEdgeState forceAtlasState') showEdges
-- Automatic opening of sidebar when a node is selected (but only first time).
R.useEffect' $ do
if
fst props.showSidePanel == GET.InitialClosed && (not Set.isEmpty $ fst props.selectedNodeIds
) then
snd props.showSidePanel $ \_ -> GET.Opened GET.SideTabData
if
showSidePanel' == GET.InitialClosed && (not Set.isEmpty selectedNodeIds'
) then
T2.write_ (GET.Opened GET.SideTabData) showSidePanel
else
pure unit
-- Timer to turn off the initial FA. This is because FA eats up lot of
-- CPU, has memory leaks etc.
R.useEffect1'
(fst props.forceAtlasState)
$ do
if
(fst props.forceAtlasState)
== SigmaxT.InitialRunning then do
R.useEffect1'
forceAtlasState'
$ do
if
forceAtlasState'
== SigmaxT.InitialRunning then do
timeoutId <- setTimeout 9000 $ do
let (toggled /\ setToggled) = props.forceAtlasState
case toggled of
SigmaxT.InitialRunning -> setToggled $ const SigmaxT.Paused
case forceAtlasState' of
SigmaxT.InitialRunning ->
T2.write_ SigmaxT.Paused forceAtlasState
_ -> pure unit
R.setRef mFAPauseRef Nothing
R.setRef mFAPauseRef $ Just timeoutId
...
...
@@ -123,83 +146,87 @@ controlsCpt = here.component "controls" cpt
else
pure unit
let edgesConfluenceSorted = A.sortWith (_.confluence) $ Seq.toUnfoldable $ SigmaxT.graphEdges
props.
graph
let edgesConfluenceSorted = A.sortWith (_.confluence) $ Seq.toUnfoldable $ SigmaxT.graphEdges 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 $ SigmaxT.graphEdges
props.
graph
--let edgesWeightSorted = A.sortWith (_.weight) $ Seq.toUnfoldable $ SigmaxT.graphEdges 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 edgeWeightRange = Range.Closed {
min: 0.0
, max: I.toNumber $ Seq.length $ SigmaxT.graphEdges
props.
graph
, max: I.toNumber $ Seq.length $ SigmaxT.graphEdges graph
}
let nodesSorted = A.sortWith (_.size) $ Seq.toUnfoldable $ SigmaxT.graphNodes
props.
graph
let nodesSorted = A.sortWith (_.size) $ Seq.toUnfoldable $ SigmaxT.graphNodes graph
let nodeSizeMin = maybe 0.0 _.size $ A.head nodesSorted
let nodeSizeMax = maybe 100.0 _.size $ A.last nodesSorted
let nodeSizeRange = Range.Closed { min: nodeSizeMin, max: nodeSizeMax }
pure $ case
getShowControls props
of
pure $ case
showControls'
of
false -> RH.div {} []
-- true -> R2.menu { id: "toolbar" } [
true -> RH.nav { className: "navbar navbar-expand-lg" }
[ RH.ul { className: "navbar-nav mx-auto" } [ -- change type button (?)
RH.li { className: "nav-item" } [ centerButton props.sigmaRef ]
, RH.li { className: "nav-item" } [ pauseForceAtlasButton {state: props.forceAtlasState} ]
, RH.li { className: "nav-item" } [ edgesToggleButton {state: props.showEdges} ]
, RH.li { className: "nav-item" } [ louvainToggleButton props.showLouvain ]
, RH.li { className: "nav-item" } [ edgeConfluenceControl edgeConfluenceRange props.edgeConfluence ]
, RH.li { className: "nav-item" } [ edgeWeightControl edgeWeightRange props.edgeWeight ]
RH.li { className: "nav-item" } [ centerButton sigmaRef ]
, RH.li { className: "nav-item" } [ pauseForceAtlasButton { state: forceAtlasState } [] ]
, RH.li { className: "nav-item" } [ edgesToggleButton { state: showEdges } [] ]
, RH.li { className: "nav-item" } [ louvainToggleButton { state: showLouvain } [] ]
, RH.li { className: "nav-item" } [ edgeConfluenceControl { range: edgeConfluenceRange
, state: edgeConfluence } [] ]
, RH.li { className: "nav-item" } [ edgeWeightControl { range: edgeWeightRange
, state: edgeWeight } [] ]
-- change level
-- file upload
-- run demo
-- search button
-- search topics
, RH.li { className: "nav-item" } [ labelSizeButton props.sigmaRef localControls.labelSize ] -- labels size: 1-4
, RH.li { className: "nav-item" } [ nodeSizeControl nodeSizeRange props.nodeSize ]
, RH.li { className: "nav-item" } [ labelSizeButton sigmaRef localControls.labelSize ] -- labels size: 1-4
, RH.li { className: "nav-item" } [ nodeSizeControl { range: nodeSizeRange
, state: nodeSize } [] ]
-- zoom: 0 -100 - calculate ratio
, RH.li { className: "nav-item" } [ multiSelectEnabledButton
props.multiSelectEnabled
] -- toggle multi node selection
, RH.li { className: "nav-item" } [ multiSelectEnabledButton
{ state: multiSelectEnabled } []
] -- toggle multi node selection
-- save button
, RH.li { className: "nav-item" } [ nodeSearchControl { graph: props.graph
, multiSelectEnabled: props.multiSelectEnabled
, selectedNodeIds: props.selectedNodeIds } ]
, RH.li { className: "nav-item" } [ mouseSelectorSizeButton props.sigmaRef localControls.mouseSelectorSize ]
, RH.li { className: "nav-item" } [ cameraButton { id: props.graphId
, hyperdataGraph: props.hyperdataGraph
, session: props.session
, sigmaRef: props.sigmaRef
, reloadForest: props.reloadForest } ]
, RH.li { className: "nav-item" }
[ nodeSearchControl { graph: graph
, multiSelectEnabled: multiSelectEnabled
, selectedNodeIds: selectedNodeIds } [] ]
, RH.li { className: "nav-item" } [ mouseSelectorSizeButton sigmaRef localControls.mouseSelectorSize ]
, RH.li { className: "nav-item" } [ cameraButton { id: graphId
, hyperdataGraph: hyperdataGraph
, session: session
, sigmaRef: sigmaRef
, reloadForest: reloadForest } ]
]
]
-- RH.ul {} [ -- change type button (?)
-- RH.li {} [ centerButton
props.
sigmaRef ]
-- , RH.li {} [ pauseForceAtlasButton {state:
props.
forceAtlasState} ]
-- , RH.li {} [ edgesToggleButton {state:
props.
showEdges} ]
-- , RH.li {} [ louvainToggleButton
props.
showLouvain ]
-- , RH.li {} [ edgeConfluenceControl edgeConfluenceRange
props.
edgeConfluence ]
-- , RH.li {} [ edgeWeightControl edgeWeightRange
props.
edgeWeight ]
-- RH.li {} [ centerButton sigmaRef ]
-- , RH.li {} [ pauseForceAtlasButton {state: forceAtlasState} ]
-- , RH.li {} [ edgesToggleButton {state: showEdges} ]
-- , RH.li {} [ louvainToggleButton showLouvain ]
-- , RH.li {} [ edgeConfluenceControl edgeConfluenceRange edgeConfluence ]
-- , RH.li {} [ edgeWeightControl edgeWeightRange edgeWeight ]
-- -- change level
-- -- file upload
-- -- run demo
-- -- search button
-- -- search topics
-- , RH.li {} [ labelSizeButton
props.
sigmaRef localControls.labelSize ] -- labels size: 1-4
-- , RH.li {} [ nodeSizeControl nodeSizeRange
props.
nodeSize ]
-- , RH.li {} [ labelSizeButton sigmaRef localControls.labelSize ] -- labels size: 1-4
-- , RH.li {} [ nodeSizeControl nodeSizeRange nodeSize ]
-- -- zoom: 0 -100 - calculate ratio
-- , RH.li {} [ multiSelectEnabledButton
props.
multiSelectEnabled ] -- toggle multi node selection
-- , RH.li {} [ multiSelectEnabledButton multiSelectEnabled ] -- toggle multi node selection
-- -- save button
-- , RH.li {} [ nodeSearchControl { graph:
props.
graph
-- , multiSelectEnabled:
props.
multiSelectEnabled
-- , selectedNodeIds:
props.
selectedNodeIds } ]
-- , RH.li {} [ mouseSelectorSizeButton
props.
sigmaRef localControls.mouseSelectorSize ]
-- , RH.li {} [ cameraButton { id:
props.
graphId
-- , hyperdataGraph:
props.
hyperdataGraph
-- , session:
props.
session
-- , sigmaRef:
props.
sigmaRef
-- , reloadForest:
props.
reloadForest } ]
-- , RH.li {} [ nodeSearchControl { graph: graph
-- , multiSelectEnabled: multiSelectEnabled
-- , selectedNodeIds: selectedNodeIds } ]
-- , RH.li {} [ mouseSelectorSizeButton sigmaRef localControls.mouseSelectorSize ]
-- , RH.li {} [ cameraButton { id: graphId
-- , hyperdataGraph: hyperdataGraph
-- , session: session
-- , sigmaRef: sigmaRef
-- , reloadForest: reloadForest } ]
-- ]
-- ]
...
...
@@ -256,14 +283,8 @@ useGraphControls { forceAtlasS
, reloadForest
}
getShowControls :: Record Controls -> Boolean
getShowControls { showControls: ( should /\ _ ) } = should
getShowTree :: Record Controls -> Boolean
getShowTree { showTree: ( should /\ _ ) } = should
setShowControls :: Record Controls -> Boolean -> Effect Unit
setShowControls { showControls
: ( _ /\ set ) } v = set $ const v
setShowControls { showControls
} v = T2.write_ v showControls
setShowTree :: Record Controls -> Boolean -> Effect Unit
setShowTree { showTree
: ( _ /\ set ) } v = set $ not <<< const v
setShowTree { showTree
} v = T2.write_ (not v) showTree
src/Gargantext/Components/GraphExplorer/RangeControl.purs
View file @
1b753ff9
...
...
@@ -10,11 +10,14 @@ import Prelude
import Data.Tuple.Nested ((/\))
import Reactix as R
import Reactix.DOM.HTML as H
import Toestand as T
import Gargantext.Components.RangeSlider as RS
import Gargantext.Utils.Range as Range
import Gargantext.Utils.Reactix as R2
import Gargantext.Utils.Toestand as T2
here :: R2.Here
here = R2.here "Gargantext.Components.GraphExplorer.RangeControl"
type Props = (
...
...
@@ -22,8 +25,8 @@ type Props = (
, sliderProps :: Record RS.Props
)
rangeControl :: R
ecord Props -> R.Element
rangeControl
props = R.createElement rangeControlCpt props []
rangeControl :: R
2.Component Props
rangeControl
= R.createElement rangeControlCpt
rangeControlCpt :: R.Component Props
rangeControlCpt = here.component "rangeButton" cpt
...
...
@@ -35,47 +38,86 @@ rangeControlCpt = here.component "rangeButton" cpt
, RS.rangeSlider sliderProps
]
edgeConfluenceControl :: Range.NumberRange -> R.State Range.NumberRange -> R.Element
edgeConfluenceControl (Range.Closed { min, max }) (state /\ setState) =
rangeControl {
caption: "Edge Confluence Weight"
, sliderProps: {
bounds: Range.Closed { min, max }
, initialValue: state
, epsilon: 0.01
, step: 1.0
, width: 10.0
, height: 5.0
, onChange: setState <<< const
}
}
edgeWeightControl :: Range.NumberRange -> R.State Range.NumberRange -> R.Element
edgeWeightControl (Range.Closed { min, max }) (state /\ setState) =
rangeControl {
caption: "Edge Weight"
, sliderProps: {
bounds: Range.Closed { min, max }
, initialValue: state
, epsilon: 1.0
, step: 1.0
, width: 10.0
, height: 5.0
, onChange: setState <<< const
}
}
nodeSizeControl :: Range.NumberRange -> R.State Range.NumberRange -> R.Element
nodeSizeControl (Range.Closed { min, max }) (state /\ setState) =
rangeControl {
caption: "Node Size"
, sliderProps: {
bounds: Range.Closed { min, max }
, initialValue: state
, epsilon: 0.1
, step: 1.0
, width: 10.0
, height: 5.0
, onChange: setState <<< const
}
}
type EdgeConfluenceControlProps = (
range :: Range.NumberRange
, state :: T.Cursor Range.NumberRange
)
edgeConfluenceControl :: R2.Component EdgeConfluenceControlProps
edgeConfluenceControl = R.createElement edgeConfluenceControlCpt
edgeConfluenceControlCpt :: R.Component EdgeConfluenceControlProps
edgeConfluenceControlCpt = here.component "edgeConfluenceControl" cpt
where
cpt { range: Range.Closed { min, max }
, state } _ = do
state' <- T.useLive T.unequal state
pure $ rangeControl {
caption: "Edge Confluence Weight"
, sliderProps: {
bounds: Range.Closed { min, max }
, initialValue: state'
, epsilon: 0.01
, step: 1.0
, width: 10.0
, height: 5.0
, onChange: \rng -> T2.write_ rng state
}
} []
type EdgeWeightControlProps = (
range :: Range.NumberRange
, state :: T.Cursor Range.NumberRange
)
edgeWeightControl :: R2.Component EdgeWeightControlProps
edgeWeightControl = R.createElement edgeWeightControlCpt
edgeWeightControlCpt :: R.Component EdgeWeightControlProps
edgeWeightControlCpt = here.component "edgeWeightControl" cpt
where
cpt { range: Range.Closed { min, max }
, state } _ = do
state' <- T.useLive T.unequal state
pure $ rangeControl {
caption: "Edge Weight"
, sliderProps: {
bounds: Range.Closed { min, max }
, initialValue: state'
, epsilon: 1.0
, step: 1.0
, width: 10.0
, height: 5.0
, onChange: \rng -> T2.write_ rng state
}
} []
type NodeSideControlProps = (
range :: Range.NumberRange
, state :: T.Cursor Range.NumberRange
)
nodeSizeControl :: R2.Component NodeSideControlProps
nodeSizeControl = R.createElement nodeSizeControlCpt
nodeSizeControlCpt :: R.Component NodeSideControlProps
nodeSizeControlCpt = here.component "nodeSizeControl" cpt
where
cpt { range: Range.Closed { min, max }
, state } _ = do
state' <- T.useLive T.unequal state
pure $ rangeControl {
caption: "Node Size"
, sliderProps: {
bounds: Range.Closed { min, max }
, initialValue: state'
, epsilon: 0.1
, step: 1.0
, width: 10.0
, height: 5.0
, onChange: \rng -> T2.write_ rng state
}
} []
src/Gargantext/Components/GraphExplorer/Search.purs
View file @
1b753ff9
...
...
@@ -11,18 +11,21 @@ import DOM.Simple.Console (log2)
import Effect (Effect)
import Reactix as R
import Reactix.DOM.HTML as H
import Toestand as T
import Gargantext.Components.InputWithAutocomplete (inputWithAutocomplete)
import Gargantext.Hooks.Sigmax.Types as SigmaxT
import Gargantext.Utils (queryMatchesLabel)
import Gargantext.Utils.Reactix as R2
import Gargantext.Utils.Toestand as T2
here :: R2.Here
here = R2.here "Gargantext.Components.GraphExplorer.Search"
type Props = (
graph :: SigmaxT.SGraph
, multiSelectEnabled ::
R.State
Boolean
, selectedNodeIds
:: R.State
SigmaxT.NodeIds
graph
:: SigmaxT.SGraph
, multiSelectEnabled ::
T.Cursor
Boolean
, selectedNodeIds
:: T.Cursor
SigmaxT.NodeIds
)
-- | Whether a node matches a search string
...
...
@@ -33,24 +36,25 @@ searchNodes :: String -> Seq.Seq (Record SigmaxT.Node) -> Seq.Seq (Record Sigmax
searchNodes "" _ = Seq.empty
searchNodes s nodes = Seq.filter (nodeMatchesSearch s) nodes
nodeSearchControl :: R
ecord Props -> R.Element
nodeSearchControl
props = R.createElement sizeButtonCpt props []
nodeSearchControl :: R
2.Component Props
nodeSearchControl
= R.createElement sizeButtonCpt
sizeButtonCpt :: R.Component Props
sizeButtonCpt = here.component "nodeSearchControl" cpt
where
cpt {
graph, multiSelectEnabled, selectedNodeIds
} _ = do
cpt {
graph, multiSelectEnabled, selectedNodeIds
} _ = do
search@(search' /\ setSearch) <- R.useState' ""
multiSelectEnabled' <- T.useLive T.unequal multiSelectEnabled
pure $
H.div { className: "form-group" }
[ H.div { className: "input-group" }
[ inputWithAutocomplete { autocompleteSearch: autocompleteSearch graph
, onAutocompleteClick: \s -> triggerSearch graph s multiSelectEnabled selectedNodeIds
, onEnterPress: \s -> triggerSearch graph s multiSelectEnabled selectedNodeIds
, onAutocompleteClick: \s -> triggerSearch graph s multiSelectEnabled
'
selectedNodeIds
, onEnterPress: \s -> triggerSearch graph s multiSelectEnabled
'
selectedNodeIds
, state: search }
, H.div { className: "btn input-group-addon"
, on: { click: \_ -> triggerSearch graph search' multiSelectEnabled selectedNodeIds }
, on: { click: \_ -> triggerSearch graph search' multiSelectEnabled
'
selectedNodeIds }
}
[ H.span { className: "fa fa-search" } [] ]
]
...
...
@@ -63,14 +67,14 @@ autocompleteSearch graph s = Seq.toUnfoldable $ (_.label) <$> searchNodes s node
triggerSearch :: SigmaxT.SGraph
-> String
->
R.State
Boolean
->
R.State
SigmaxT.NodeIds
-> Boolean
->
T.Cursor
SigmaxT.NodeIds
-> Effect Unit
triggerSearch graph search
(multiSelectEnabled /\ _) (_ /\ setNodeIds)
= do
triggerSearch graph search
multiSelectEnabled selectedNodeIds
= do
let graphNodes = SigmaxT.graphNodes graph
let matching = Set.fromFoldable $ (_.id) <$> searchNodes search graphNodes
log2 "[triggerSearch] search" search
setNodeIds $
\nodes ->
Set.union matching $ if multiSelectEnabled then nodes else SigmaxT.emptyNodeIds
T2.modify_ (
\nodes ->
Set.union matching $ if multiSelectEnabled then nodes else SigmaxT.emptyNodeIds
) selectedNodeIds
src/Gargantext/Components/GraphExplorer/Sidebar.purs
View file @
1b753ff9
...
...
@@ -18,6 +18,8 @@ import Partial.Unsafe (unsafePartial)
import Reactix as R
import Reactix.DOM.HTML as RH
import Reactix.DOM.HTML as H
import Record as Record
import Record.Extra as RX
import Toestand as T
import Gargantext.Prelude
...
...
@@ -34,7 +36,7 @@ import Gargantext.Data.Array (mapMaybe)
import Gargantext.Ends (Frontends)
import Gargantext.Hooks.Sigmax.Types as SigmaxT
import Gargantext.Sessions (Session)
import Gargantext.Types (CTabNgramType, TabSubType(..), TabType(..), TermList(..), modeTabType)
import Gargantext.Types (CTabNgramType,
NodeID,
TabSubType(..), TabType(..), TermList(..), modeTabType)
import Gargantext.Utils.Reactix as R2
import Gargantext.Utils.Reload as GUR
import Gargantext.Utils.Toestand as T2
...
...
@@ -42,17 +44,21 @@ import Gargantext.Utils.Toestand as T2
here :: R2.Here
here = R2.here "Gargantext.Components.GraphExplorer.Sidebar"
type Props = (
frontends :: Frontends
, graph :: SigmaxT.SGraph
, graphId :: Int
, graphVersion :: GUR.ReloadS
type Common = (
graphId :: NodeID
, metaData :: GET.MetaData
, reloadForest :: T.Cursor T2.Reload
, removedNodeIds :: T.Cursor SigmaxT.NodeIds
, selectedNodeIds :: T.Cursor SigmaxT.NodeIds
, session :: Session
)
type Props = (
frontends :: Frontends
, graph :: SigmaxT.SGraph
, graphVersion :: GUR.ReloadS
, showSidePanel :: T.Cursor GET.SidePanelState
| Common
)
sidebar :: Record Props -> R.Element
...
...
@@ -61,15 +67,26 @@ sidebar props = R.createElement sidebarCpt props []
sidebarCpt :: R.Component Props
sidebarCpt = here.component "sidebar" cpt
where
cpt {showSidePanel: (GET.Closed /\ _)} _children = do
pure $ RH.div {} []
cpt {showSidePanel: (GET.InitialClosed /\ _)} _children = do
pure $ RH.div {} []
cpt props@{metaData, showSidePanel} _children = do
pure $ RH.div { id: "sp-container" }
[ sideTabNav showSidePanel [SideTabLegend, SideTabData, SideTabCommunity]
, sideTab (fst showSidePanel) props
]
cpt props@{ metaData, showSidePanel } _ = do
showSidePanel' <- T.useLive T.unequal showSidePanel
case showSidePanel' of
GET.Closed -> pure $ RH.div {} []
GET.InitialClosed -> pure $ RH.div {} []
GET.Opened sideTabT -> do
let sideTab' = case sideTabT of
SideTabLegend -> sideTabLegend sideTabProps []
SideTabData -> sideTabData sideTabProps []
SideTabCommunity -> sideTabCommunity sideTabProps []
_ -> H.div {} []
pure $ RH.div { id: "sp-container" }
[ sideTabNav { sidePanel: showSidePanel
, sideTabs: [SideTabLegend, SideTabData, SideTabCommunity] } []
, sideTab'
]
where
sideTabProps = RX.pick props :: Record SideTabProps
type SideTabNavProps = (
sidePanel :: T.Cursor GET.SidePanelState
...
...
@@ -101,142 +118,217 @@ sideTabNavCpt = here.component "sideTabNav" cpt
}
} [ H.text $ show tab ]
type SideTabProps = (
frontends :: Frontends
, metaData :: GET.MetaData
)
type SideTabProps = Props
sideTab :: SidePanelState -> Record Props -> R.Element
sideTab (Opened SideTabLegend) props@{metaData} =
H.div {} [ let (GET.MetaData {legend}) = metaData
in Legend.legend { items: Seq.fromFoldable legend}
, documentation EN
]
sideTabLegend :: R2.Component SideTabProps
sideTabLegend = R.createElement sideTabLegendCpt
sideTab (Opened SideTabData) props =
RH.div {} [ selectedNodes props (SigmaxT.nodesGraphMap props.graph)
, neighborhood props
, RH.div { className: "col-md-12", id: "query" }
[ query SearchDoc
props.frontends
props.metaData
props.session
(SigmaxT.nodesGraphMap props.graph)
selectedNodeIds'
]
]
where
sideTabLegendCpt :: R.Component SideTabProps
sideTabLegendCpt = here.component "sideTabLegend" cpt
where
cpt props@{ metaData: GET.MetaData { legend } } _ = do
pure $ H.div {}
[ Legend.legend { items: Seq.fromFoldable legend }
, documentation EN
]
sideTabData :: R2.Component SideTabProps
sideTabData = R.createElement sideTabDataCpt
checkbox text =
RH.li {}
[ RH.span {} [ RH.text text ]
, RH.input { type: "checkbox"
, className: "checkbox"
, defaultChecked: true
, title: "Mark as completed" } ]
sideTabDataCpt :: R.Component SideTabProps
sideTabDataCpt = here.component "sideTabData" cpt
where
cpt props _ = do
selectedNodeIds' <- T.useLive T.unequal props.selectedNodeIds
pure $ RH.div {}
[ selectedNodes (Record.merge { nodesMap: SigmaxT.nodesGraphMap props.graph } props) []
, neighborhood props []
, RH.div { className: "col-md-12", id: "query" }
[ query SearchDoc
props.frontends
props.metaData
props.session
(SigmaxT.nodesGraphMap props.graph)
selectedNodeIds'
]
]
where
checkbox text = RH.li {}
[ RH.span {} [ RH.text text ]
, RH.input { type: "checkbox"
, className: "checkbox"
, defaultChecked: true
, title: "Mark as completed" } ]
sideTab (Opened SideTabCommunity) props =
RH.div { className: "col-md-12", id: "query" }
[ selectedNodes props (SigmaxT.nodesGraphMap props.graph)
, neighborhood props
, query SearchContact
props.frontends
props.metaData
props.session
(SigmaxT.nodesGraphMap props.graph)
props.selectedNodeIds
]
sideTabCommunity :: R2.Component SideTabProps
sideTabCommunity = R.createElement sideTabCommunityCpt
sideTab _ _ = H.div {} []
sideTabCommunityCpt :: R.Component SideTabProps
sideTabCommunityCpt = here.component "sideTabCommunity" cpt
where
cpt props _ = do
selectedNodeIds' <- T.useLive T.unequal props.selectedNodeIds
pure $ RH.div { className: "col-md-12", id: "query" }
[ selectedNodes (Record.merge { nodesMap: SigmaxT.nodesGraphMap props.graph } props) []
, neighborhood props []
, query SearchContact
props.frontends
props.metaData
props.session
(SigmaxT.nodesGraphMap props.graph)
selectedNodeIds'
]
-------------------------------------------
-- TODO
-- selectedNodes :: Record Props -> Map.Map String Nodes -> R.Element
selectedNodes props nodesMap =
R2.row [ R2.col 12
type SelectedNodesProps = (
nodesMap :: SigmaxT.NodesMap
| Props
)
selectedNodes :: R2.Component SelectedNodesProps
selectedNodes = R.createElement selectedNodesCpt
selectedNodesCpt :: R.Component SelectedNodesProps
selectedNodesCpt = here.component "selectedNodes" cpt
where
cpt props@{ graph
, nodesMap
, selectedNodeIds } _ = do
selectedNodeIds' <- T.useLive T.unequal selectedNodeIds
pure $ R2.row
[ R2.col 12
[ RH.ul { className: "nav nav-tabs d-flex justify-content-center"
, id: "myTab"
, role: "tablist" }
[ RH.div { className: "tab-content" }
[ RH.div { className: "d-flex flex-wrap justify-content-center"
, role: "tabpanel" }
( Seq.toUnfoldable
$ ( Seq.map (badge props.
selectedNodeIds)
(badges props.graph props.selectedNodeIds
)
)
)
( Seq.toUnfoldable
$ ( Seq.map (badge
selectedNodeIds)
(badges graph selectedNodeIds'
)
)
)
, H.br {}
]
]
, RH.div { className: "tab-content flex-space-between" }
[ removeButton "primary" "Move as candidate" CandidateTerm props nodesMap
, H.br {}
, removeButton "danger" "Move as stop" StopTerm props nodesMap
]
]
]
neighborhood props = RH.div { className: "tab-content", id: "myTabContent" }
[ RH.div { -- className: "flex-space-around d-flex justify-content-center"
className: "d-flex flex-wrap flex-space-around"
, id: "home"
, role: "tabpanel"
}
(Seq.toUnfoldable $ Seq.map (badge props.selectedNodeIds)
$ neighbourBadges props.graph props.selectedNodeIds
)
]
removeButton btnType text rType props' nodesMap' =
if Set.isEmpty $ fst props'.selectedNodeIds then
RH.div {} []
else
RH.button { className: "btn btn-sm btn-" <> btnType
, on: { click: onClickRemove rType props' nodesMap' }
}
[ RH.text text ]
onClickRemove rType props' nodesMap' e = do
let nodes = mapMaybe (\id -> Map.lookup id nodesMap')
$ Set.toUnfoldable $ fst props'.selectedNodeIds
deleteNodes { graphId: props'.graphId
, metaData: props'.metaData
, nodes
, session: props'.session
, termList: rType
, reloadForest: props'.reloadForest }
snd props'.removedNodeIds $ const $ fst props'.selectedNodeIds
snd props'.selectedNodeIds $ const SigmaxT.emptyNodeIds
, RH.div { className: "tab-content flex-space-between" }
[ removeButton (Record.merge { buttonType: "primary"
, rType: CandidateTerm
, nodesMap
, text: "Move as candidate" } commonProps) []
, H.br {}
, removeButton (Record.merge { buttonType: "danger"
, nodesMap
, rType: StopTerm
, text: "Move as stop" } commonProps) []
]
]
]
where
commonProps = RX.pick props :: Record Common
neighborhood :: R2.Component Props
neighborhood = R.createElement neighborhoodCpt
neighborhoodCpt :: R.Component Props
neighborhoodCpt = here.component "neighborhood" cpt
where
cpt { graph
, selectedNodeIds } _ = do
selectedNodeIds' <- T.useLive T.unequal selectedNodeIds
pure $ RH.div { className: "tab-content", id: "myTabContent" }
[ RH.div { -- className: "flex-space-around d-flex justify-content-center"
className: "d-flex flex-wrap flex-space-around"
, id: "home"
, role: "tabpanel"
}
(Seq.toUnfoldable $ Seq.map (badge selectedNodeIds)
$ neighbourBadges graph selectedNodeIds'
)
]
type RemoveButtonProps = (
buttonType :: String
, nodesMap :: SigmaxT.NodesMap
, rType :: TermList
, text :: String
| Common
)
removeButton :: R2.Component RemoveButtonProps
removeButton = R.createElement removeButtonCpt
removeButtonCpt :: R.Component RemoveButtonProps
removeButtonCpt = here.component "removeButton" cpt
where
cpt { buttonType
, graphId
, metaData
, nodesMap
, reloadForest
, removedNodeIds
, rType
, selectedNodeIds
, session
, text } _ = do
selectedNodeIds' <- T.useLive T.unequal selectedNodeIds
pure $ if Set.isEmpty selectedNodeIds' then
RH.div {} []
else
RH.button { className: "btn btn-sm btn-" <> buttonType
, on: { click: onClickRemove selectedNodeIds' }
} [ RH.text text ]
where
onClickRemove selectedNodeIds' e = do
let nodes = mapMaybe (\id -> Map.lookup id nodesMap)
$ Set.toUnfoldable selectedNodeIds'
deleteNodes { graphId: graphId
, metaData: metaData
, nodes
, session: session
, termList: rType
, reloadForest }
T2.write_ selectedNodeIds' removedNodeIds
T2.write_ SigmaxT.emptyNodeIds selectedNodeIds
badge :: T.Cursor SigmaxT.NodeIds -> Record SigmaxT.Node -> R.Element
badge
(_ /\ setNodeIds)
{id, label} =
badge
selectedNodeIds
{id, label} =
RH.a { className: "badge badge-pill badge-light"
, on: { click: onClick }
} [ RH.h6 {} [ RH.text label ] ]
where
onClick e = do
setNodeIds $ const $ Set.singleton id
T2.write_ (Set.singleton id) selectedNodeIds
badges :: SigmaxT.SGraph ->
T.Cursor
SigmaxT.NodeIds -> Seq.Seq (Record SigmaxT.Node)
badges graph
(selectedNodeIds /\ _)
= SigmaxT.graphNodes $ SigmaxT.nodesById graph selectedNodeIds
badges :: SigmaxT.SGraph -> SigmaxT.NodeIds -> Seq.Seq (Record SigmaxT.Node)
badges graph
selectedNodeIds
= SigmaxT.graphNodes $ SigmaxT.nodesById graph selectedNodeIds
neighbourBadges :: SigmaxT.SGraph ->
T.Cursor
SigmaxT.NodeIds -> Seq.Seq (Record SigmaxT.Node)
neighbourBadges graph
(selectedNodeIds /\ _)
= SigmaxT.neighbours graph selectedNodes
neighbourBadges :: SigmaxT.SGraph -> SigmaxT.NodeIds -> Seq.Seq (Record SigmaxT.Node)
neighbourBadges graph
selectedNodeIds
= SigmaxT.neighbours graph selectedNodes
where
selectedNodes = SigmaxT.graphNodes $ SigmaxT.nodesById graph selectedNodeIds
type DeleteNodes =
( graphId
:: Int
, metaData :: GET.MetaData
, nodes :: Array (Record SigmaxT.Node)
,
session :: Session
,
termList :: TermList
,
reloadForest :: GUR.ReloadS
( graphId
:: NodeID
, metaData
:: GET.MetaData
, nodes
:: Array (Record SigmaxT.Node)
,
reloadForest :: T.Cursor T2.Reload
,
session :: Session
,
termList :: TermList
)
deleteNodes :: Record DeleteNodes -> Effect Unit
...
...
@@ -247,7 +339,7 @@ deleteNodes { graphId, metaData, nodes, session, termList, reloadForest } = do
case mPatch of
Nothing -> pure unit
Just (NTC.Versioned patch) -> do
liftEffect $ GUR.bump reloadForest
liftEffect $ GUR.bump
Cursor
reloadForest
-- Why is this called delete node?
deleteNode :: TermList
...
...
@@ -260,7 +352,7 @@ deleteNode termList session (GET.MetaData metaData) node = do
task <- NTC.postNgramsChartsAsync coreParams -- TODO add task
pure ret
where
nodeId ::
Int
nodeId ::
NodeID
nodeId = unsafePartial $ fromJust $ fromString node.id
versioned :: NTC.VersionedNgramsPatches
...
...
src/Gargantext/Components/GraphExplorer/SlideButton.purs
View file @
1b753ff9
...
...
@@ -11,19 +11,22 @@ import Data.Tuple.Nested ((/\))
import Effect (Effect)
import Reactix as R
import Reactix.DOM.HTML as H
import Toestand as T
import Gargantext.Hooks.Sigmax as Sigmax
import Gargantext.Hooks.Sigmax.Sigma as Sigma
import Gargantext.Utils.Reactix as R2
import Gargantext.Utils.Toestand as T2
here :: R2.Here
here = R2.here "Gargantext.Components.GraphExplorer.SlideButton"
type Props = (
state :: R.State Number
, caption :: String
, min :: Number
, max :: Number
caption :: String
, min :: Number
, max :: Number
, onChange :: forall e. e -> Effect Unit
, state :: T.Cursor Number
)
sizeButton :: Record Props -> R.Element
...
...
@@ -33,7 +36,7 @@ sizeButtonCpt :: R.Component Props
sizeButtonCpt = here.component "sizeButton" cpt
where
cpt {state, caption, min, max, onChange} _ = do
let (value /\ setValue) =
state
state' <- T.useLive T.unequal
state
pure $
H.span { class: "range-simple" }
[ H.label {} [ R2.small {} [ H.text caption ] ]
...
...
@@ -41,12 +44,12 @@ sizeButtonCpt = here.component "sizeButton" cpt
, className: "form-control"
, min: show min
, max: show max
, defaultValue:
value
, defaultValue:
state'
, on: {input: onChange}
}
]
labelSizeButton :: R.Ref Sigmax.Sigma ->
R.State
Number -> R.Element
labelSizeButton :: R.Ref Sigmax.Sigma ->
T.Cursor
Number -> R.Element
labelSizeButton sigmaRef state =
sizeButton {
state
...
...
@@ -56,7 +59,6 @@ labelSizeButton sigmaRef state =
, onChange: \e -> do
let sigma = R.readRef sigmaRef
let newValue = readFloat $ R.unsafeEventValue e
let (_ /\ setValue) = state
Sigmax.dependOnSigma sigma "[labelSizeButton] sigma: Nothing" $ \s -> do
Sigma.setSettings s {
defaultLabelSize: newValue
...
...
@@ -64,10 +66,10 @@ labelSizeButton sigmaRef state =
, maxNodeSize: newValue / 2.5
--, labelSizeRatio: newValue / 2.5
}
setValue $ const newValu
e
T2.write_ newValue stat
e
}
mouseSelectorSizeButton :: R.Ref Sigmax.Sigma ->
R.State
Number -> R.Element
mouseSelectorSizeButton :: R.Ref Sigmax.Sigma ->
T.Cursor
Number -> R.Element
mouseSelectorSizeButton sigmaRef state =
sizeButton {
state
...
...
@@ -76,11 +78,10 @@ mouseSelectorSizeButton sigmaRef state =
, max: 50.0
, onChange: \e -> do
let sigma = R.readRef sigmaRef
let (_ /\ setValue) = state
let newValue = readFloat $ R.unsafeEventValue e
Sigmax.dependOnSigma sigma "[mouseSelectorSizeButton] sigma: Nothing" $ \s -> do
Sigma.setSettings s {
mouseSelectorSize: newValue
}
setValue $ const newValu
e
T2.write_ newValue stat
e
}
src/Gargantext/Components/GraphExplorer/ToggleButton.purs
View file @
1b753ff9
...
...
@@ -16,64 +16,83 @@ import Prelude
import Data.Tuple (snd)
import Data.Tuple.Nested ((/\))
import Effect (Effect)
import Reactix as R
import Reactix.DOM.HTML as H
import Toestand as T
import Gargantext.Components.GraphExplorer.Types as GET
import Gargantext.Hooks.Sigmax.Types as SigmaxTypes
import Gargantext.Utils.Reactix as R2
import Reactix as R
import Reactix.DOM.HTML as H
import Gargantext.Utils.Toestand as T2
here :: R2.Here
here = R2.here "Gargantext.Components.GraphExplorer.ToggleButton"
type Props = (
state
:: R.State
Boolean
, onMessage :: String
state
:: T.Cursor
Boolean
, onMessage
:: String
, offMessage :: String
, style :: String
, onClick :: forall e. e -> Effect Unit
, onClick
:: forall e. e -> Effect Unit
)
toggleButton :: R
ecord Props -> R.Element
toggleButton
props = R.createElement toggleButtonCpt props []
toggleButton :: R
2.Component Props
toggleButton
= R.createElement toggleButtonCpt
toggleButtonCpt :: R.Component Props
toggleButtonCpt = here.component "toggleButton" cpt
where
cpt {state, onMessage, offMessage, onClick, style} _ = do
let (toggled /\ _) = state
pure $ H.button { className: "btn btn-outline-" <> style <> " " <> cls toggled
cpt { state
, onMessage
, offMessage
, onClick
, style } _ = do
state' <- T.useLive T.unequal state
pure $ H.button { className: "btn btn-outline-" <> style <> " " <> cls state'
, on: {click: onClick}
} [ R2.small {} [ H.text (text onMessage offMessage
toggled
) ] ]
} [ R2.small {} [ H.text (text onMessage offMessage
state'
) ] ]
cls true = "active"
cls false = ""
text on _off true = on
text _on off false = off
controlsToggleButton :: R.State Boolean -> R.Element
controlsToggleButton state =
toggleButton {
state: state
, onMessage: "Hide Controls"
, offMessage: "Show Controls"
, onClick: \_ -> snd state not
, style: "light"
}
type ControlsToggleButtonProps = (
state :: T.Cursor Boolean
)
controlsToggleButton :: R2.Component ControlsToggleButtonProps
controlsToggleButton = R.createElement controlsToggleButtonCpt
controlsToggleButtonCpt :: R.Component ControlsToggleButtonProps
controlsToggleButtonCpt = here.component "controlsToggleButton" cpt
where
cpt { state } _ = do
pure $ toggleButton {
state: state
, onMessage: "Hide Controls"
, offMessage: "Show Controls"
, onClick: \_ -> T2.modify_ not state
, style: "light"
} []
type EdgesButtonProps = (
state ::
R.State
SigmaxTypes.ShowEdgesState
state ::
T.Cursor
SigmaxTypes.ShowEdgesState
)
edgesToggleButton :: R
ecord EdgesButtonProps -> R.Element
edgesToggleButton
props = R.createElement edgesToggleButtonCpt props []
edgesToggleButton :: R
2.Component EdgesButtonProps
edgesToggleButton
= R.createElement edgesToggleButtonCpt
edgesToggleButtonCpt :: R.Component EdgesButtonProps
edgesToggleButtonCpt = here.component "edgesToggleButton" cpt
where
cpt {state: (state /\ setState)} _ = do
pure $ H.button { className: "btn btn-outline-primary " <> cls state
, on: { click: onClick setState }
} [ R2.small {} [ H.text (text state) ] ]
cpt { state } _ = do
state' <- T.useLive T.unequal state
pure $ H.button { className: "btn btn-outline-primary " <> cls state'
, on: { click: onClick state }
} [ R2.small {} [ H.text (text state') ] ]
text s = if SigmaxTypes.edgeStateHidden s then "Show edges" else "Hide edges"
...
...
@@ -81,42 +100,62 @@ edgesToggleButtonCpt = here.component "edgesToggleButton" cpt
cls _ = "active"
-- TODO: Move this to Graph.purs to the R.useEffect handler which renders nodes/edges
onClick setState _ = setState SigmaxTypes.toggleShowEdgesState
louvainToggleButton :: R.State Boolean -> R.Element
louvainToggleButton state =
toggleButton {
state: state
, onMessage: "Louvain off"
, offMessage: "Louvain on"
, onClick: \_ -> snd state not
, style: "primary"
}
multiSelectEnabledButton :: R.State Boolean -> R.Element
multiSelectEnabledButton state =
toggleButton {
state: state
, onMessage: "Single-node"
, offMessage: "Multi-node"
, onClick: \_ -> snd state not
, style : "primary"
}
onClick state _ = T2.modify_ SigmaxTypes.toggleShowEdgesState state
type LouvainToggleButtonProps = (
state :: T.Cursor Boolean
)
louvainToggleButton :: R2.Component LouvainToggleButtonProps
louvainToggleButton = R.createElement louvainToggleButtonCpt
louvainToggleButtonCpt :: R.Component LouvainToggleButtonProps
louvainToggleButtonCpt = here.component "louvainToggleButton" cpt
where
cpt { state } _ = do
pure $ toggleButton {
state: state
, onMessage: "Louvain off"
, offMessage: "Louvain on"
, onClick: \_ -> T2.modify_ not state
, style: "primary"
} []
type MultiSelectEnabledButtonProps = (
state :: T.Cursor Boolean
)
multiSelectEnabledButton :: R2.Component MultiSelectEnabledButtonProps
multiSelectEnabledButton = R.createElement multiSelectEnabledButtonCpt
multiSelectEnabledButtonCpt :: R.Component MultiSelectEnabledButtonProps
multiSelectEnabledButtonCpt = here.component "lmultiSelectEnabledButton" cpt
where
cpt { state } _ = do
pure $ toggleButton {
state: state
, onMessage: "Single-node"
, offMessage: "Multi-node"
, onClick: \_ -> T2.modify_ not state
, style : "primary"
} []
type ForceAtlasProps = (
state ::
R.State
SigmaxTypes.ForceAtlasState
state ::
T.Cursor
SigmaxTypes.ForceAtlasState
)
pauseForceAtlasButton :: R
ecord ForceAtlasProps -> R.Element
pauseForceAtlasButton
props = R.createElement pauseForceAtlasButtonCpt props []
pauseForceAtlasButton :: R
2.Component ForceAtlasProps
pauseForceAtlasButton
= R.createElement pauseForceAtlasButtonCpt
pauseForceAtlasButtonCpt :: R.Component ForceAtlasProps
pauseForceAtlasButtonCpt = here.component "forceAtlasToggleButton" cpt
where
cpt {state: (state /\ setState)} _ = do
pure $ H.button { className: "btn btn-outline-primary " <> cls state
, on: { click: onClick setState }
} [ R2.small {} [ H.text (text state) ] ]
cpt { state } _ = do
state' <- T.useLive T.unequal state
pure $ H.button { className: "btn btn-outline-primary " <> cls state'
, on: { click: onClick state }
} [ R2.small {} [ H.text (text state') ] ]
cls SigmaxTypes.InitialRunning = "active"
cls SigmaxTypes.Running = "active"
...
...
@@ -127,26 +166,43 @@ pauseForceAtlasButtonCpt = here.component "forceAtlasToggleButton" cpt
text SigmaxTypes.Running = "Pause Force Atlas"
text SigmaxTypes.Paused = "Start Force Atlas"
onClick s
etState _ = setState SigmaxTypes.toggleForceAtlasS
tate
onClick s
tate _ = T2.modify_ SigmaxTypes.toggleForceAtlasState s
tate
treeToggleButton :: R.State Boolean -> R.Element
treeToggleButton state =
toggleButton {
state: state
, onMessage: "Hide Tree"
, offMessage: "Show Tree"
, onClick: \_ -> snd state not
, style: "light"
}
type TreeToggleButtonProps = (
state :: T.Cursor Boolean
)
treeToggleButton :: R2.Component TreeToggleButtonProps
treeToggleButton = R.createElement treeToggleButtonCpt
sidebarToggleButton :: R.State GET.SidePanelState -> R.Element
sidebarToggleButton (state /\ setState) = R.createElement el {} []
treeToggleButtonCpt :: R.Component TreeToggleButtonProps
treeToggleButtonCpt = here.component "treeToggleButton" cpt
where
el = here.component "sidebarToggleButton" cpt
cpt {} _ = do
pure $ H.button { className: "btn btn-outline-light " <> cls state
, on: { click: onClick}
} [ R2.small {} [ H.text (text onMessage offMessage state) ] ]
cpt { state } _ = do
pure $ toggleButton {
state: state
, onMessage: "Hide Tree"
, offMessage: "Show Tree"
, onClick: \_ -> T2.modify_ not state
, style: "light"
} []
type SidebarToggleButtonProps = (
state :: T.Cursor GET.SidePanelState
)
sidebarToggleButton :: R2.Component SidebarToggleButtonProps
sidebarToggleButton = R.createElement sidebarToggleButtonCpt
sidebarToggleButtonCpt :: R.Component SidebarToggleButtonProps
sidebarToggleButtonCpt = here.component "sidebarToggleButton" cpt
where
cpt { state } _ = do
state' <- T.useLive T.unequal state
pure $ H.button { className: "btn btn-outline-light " <> cls state'
, on: { click: onClick state }
} [ R2.small {} [ H.text (text onMessage offMessage state') ] ]
cls (GET.Opened _) = "active"
cls _ = ""
...
...
@@ -157,8 +213,8 @@ sidebarToggleButton (state /\ setState) = R.createElement el {} []
text _on off GET.InitialClosed = off
text _on off GET.Closed = off
onClick
= \_ -> do
setState $
\s -> case s of
onClick
state = \_ ->
T2.modify_ (
\s -> case s of
GET.InitialClosed -> GET.Opened GET.SideTabLegend
GET.Closed -> GET.Opened GET.SideTabLegend
(GET.Opened _) -> GET.Closed
(GET.Opened _) -> GET.Closed
) state
src/Gargantext/Components/Login.purs
View file @
1b753ff9
...
...
@@ -21,6 +21,7 @@ import Gargantext.Hooks.Loader as GHL
import Gargantext.Sessions (Session, Sessions, Action(Logout), unSessions)
import Gargantext.Sessions as Sessions
import Gargantext.Utils.Reactix as R2
import Gargantext.Utils.Toestand as T2
here :: R2.Here
here = R2.here "Gargantext.Components.Login"
...
...
@@ -109,7 +110,7 @@ renderBackend cursor backend@(Backend {name}) =
, H.td {} [ H.a { on: { click }} [ H.text (backendLabel name) ]]
, H.td {} [ H.text $ "garg://" <> name ]] where
className = "fa fa-hand-o-right" -- "glyphitem fa fa-log-in"
click _ = T
.write
(Just backend) cursor
click _ = T
2.write_
(Just backend) cursor
backendLabel :: String -> String
backendLabel =
...
...
src/Gargantext/Components/Nodes/Corpus/Document.purs
View file @
1b753ff9
...
...
@@ -111,10 +111,10 @@ docViewCpt = here.component "docView" cpt
NodePoly {hyperdata: Document doc} = document
type LayoutProps =
( listId :: ListId
,
c
orpusId :: Maybe NodeID
, nodeId :: NodeID
, session :: R.Context Session
( listId
:: ListId
,
mC
orpusId :: Maybe NodeID
, nodeId
:: NodeID
, session
:: R.Context Session
)
documentMainLayout :: R2.Component LayoutProps
...
...
@@ -129,14 +129,14 @@ documentLayout = R.createElement documentLayoutCpt
documentLayoutCpt :: R.Component LayoutProps
documentLayoutCpt = here.component "documentLayout" cpt where
cpt { listId,
c
orpusId, nodeId, session } children = cp <$> R.useContext session where
cp s = documentLayoutWithKey { key, listId,
c
orpusId, nodeId, session: s } children where
cpt { listId,
mC
orpusId, nodeId, session } children = cp <$> R.useContext session where
cp s = documentLayoutWithKey { key, listId,
mC
orpusId, nodeId, session: s } children where
key = show (sessionId s) <> "-" <> show nodeId
type KeyLayoutProps =
( key :: String
, listId :: ListId
,
c
orpusId :: Maybe NodeID
,
mC
orpusId :: Maybe NodeID
, nodeId :: NodeID
, session :: Session
)
...
...
@@ -147,12 +147,12 @@ documentLayoutWithKey = R.createElement documentLayoutWithKeyCpt
documentLayoutWithKeyCpt :: R.Component KeyLayoutProps
documentLayoutWithKeyCpt = here.component "documentLayoutWithKey" cpt
where
cpt { listId,
c
orpusId, nodeId, session } _ = do
cpt { listId,
mC
orpusId, nodeId, session } _ = do
useLoader path loadData $ \loaded ->
docViewWrapper { loaded, path } []
where
tabType = TabDocument (TabNgramType CTabTerms)
path = { listIds: [listId],
c
orpusId, nodeId, session, tabType }
path = { listIds: [listId],
mC
orpusId, nodeId, session, tabType }
------------------------------------------------------------------------
...
...
src/Gargantext/Components/Nodes/Corpus/Document/Types.purs
View file @
1b753ff9
...
...
@@ -12,12 +12,12 @@ import Gargantext.Components.NgramsTable.Core (CoreState, Versioned(..) , Versio
import Gargantext.Sessions (Session)
import Gargantext.Types (ListId, NodeID, TabType)
type DocPath =
{ listIds
:: Array ListId
,
c
orpusId :: Maybe NodeID
, nodeId :: NodeID
, session :: Session
, tabType :: TabType
type DocPath =
{
listIds
:: Array ListId
,
mC
orpusId :: Maybe NodeID
, nodeId
:: NodeID
, session
:: Session
, tabType
:: TabType
}
type NodeDocument = NodePoly Document
...
...
src/Gargantext/Components/Nodes/Texts.purs
View file @
1b753ff9
...
...
@@ -37,8 +37,8 @@ here :: R2.Here
here = R2.here "Gargantext.Components.Nodes.Texts"
--------------------------------------------------------
type TextsWithForest
a =
( forestProps :: Record (Forest.LayoutProps a)
type TextsWithForest
= (
forestProps :: Record Forest.LayoutProps
, textsProps :: Record CommonProps
)
...
...
@@ -77,34 +77,37 @@ topBarCpt = here.component "topBar" cpt
type CommonProps =
(
frontends :: Frontends
, nodeId ::
Int
, session ::
R.Context
Session
type CommonProps =
(
frontends :: Frontends
, nodeId ::
NodeID
, session :: Session
)
type Props = ( controls :: Record TextsLayoutControls | CommonProps )
type KeyProps =
( key :: String
, controls :: Record TextsLayoutControls
, frontends :: Frontends
, nodeId :: Int
, session :: Session
)
textsLayout :: R2.Component Props
textsLayout = R.createElement textsLayoutCpt
textsLayoutCpt :: R.Component Props
textsLayoutCpt = here.component "textsLayout" cpt where
cpt { controls, frontends, nodeId, session, sessionUpdate } children = do
session' <- R.useContext session
pure $
textsLayoutWithKey
{ controls, frontends, key, nodeId, session: session' } children where
key = show sid <> "-" <> show nodeId where
sid = sessionId session
cpt { controls, frontends, nodeId, session } children = do
pure $ textsLayoutWithKey { controls
, frontends
, key
, nodeId
, session } children
where
key = show sid <> "-" <> show nodeId
where
sid = sessionId session
type KeyProps = (
key :: String
, controls :: Record TextsLayoutControls
, frontends :: Frontends
, nodeId :: NodeID
, session :: Session
)
textsLayoutWithKey :: R2.Component KeyProps
textsLayoutWithKey = R.createElement textsLayoutWithKeyCpt
...
...
@@ -112,7 +115,7 @@ textsLayoutWithKey = R.createElement textsLayoutWithKeyCpt
textsLayoutWithKeyCpt :: R.Component KeyProps
textsLayoutWithKeyCpt = here.component "textsLayoutWithKey" cpt
where
cpt { controls, frontends, nodeId, session
, sessionUpdate
} _children = do
cpt { controls, frontends, nodeId, session } _children = do
cacheState <- R.useState' $ getCacheState NT.CacheOff session nodeId
pure $ loader { nodeId, session } loadCorpusWithChild $
...
...
@@ -121,16 +124,27 @@ textsLayoutWithKeyCpt = here.component "textsLayoutWithKey" cpt
CorpusInfo { authors, desc, query } = getCorpusInfo h.fields
title = "Corpus " <> name
R.fragment
[ Table.tableHeaderLayout
{ afterCacheStateChange, cacheState, date, desc, query, title, user: authors
, key: "textsLayoutWithKey-" <> (show $ fst cacheState) }
, tabs { cacheState, corpusData, corpusId, frontends, session
[ Table.tableHeaderLayout { afterCacheStateChange
, cacheState
, date
, desc
, query
, title
, user: authors
, key: "textsLayoutWithKey-" <> (show $ fst cacheState) }
, tabs { cacheState
, corpusData
, corpusId
, frontends
, session
, sidePanelTriggers: controls.triggers }
]
where
afterCacheStateChange cacheState = do
launchAff_ $ clearCache unit
sessionUpdate $ setCacheState session nodeId cacheState
-- TODO
--sessionUpdate $ setCacheState session nodeId cacheState
--_ <- setCacheState session nodeId cacheState
data Mode = MoreLikeFav | MoreLikeTrash
...
...
@@ -148,7 +162,7 @@ modeTabType MoreLikeTrash = CTabSources -- TODO
type TabsProps =
( cacheState :: R.State NT.CacheState
, corpusData :: CorpusData
, corpusId ::
Int
, corpusId ::
NodeID
, frontends :: Frontends
, session :: Session
, sidePanelTriggers :: Record SidePanelTriggers
...
...
@@ -391,9 +405,9 @@ sidePanelCpt = here.component "sidePanel" cpt
]
type SidePanelDocView = (
c
orpusId :: Maybe NodeID
,
l
istId :: Maybe ListId
,
n
odeId :: Maybe NodeID
mC
orpusId :: Maybe NodeID
,
mL
istId :: Maybe ListId
,
mN
odeId :: Maybe NodeID
, session :: Session
)
...
...
@@ -403,15 +417,16 @@ sidePanelDocView = R.createElement sidePanelDocViewCpt
sidePanelDocViewCpt :: R.Component SidePanelDocView
sidePanelDocViewCpt = here.component "sidePanelDocView" cpt
where
cpt {
l
istId: Nothing } _ = do
cpt {
mL
istId: Nothing } _ = do
pure $ H.div {} []
cpt {
n
odeId: Nothing } _ = do
cpt {
mN
odeId: Nothing } _ = do
pure $ H.div {} []
cpt {
c
orpusId
,
l
istId: Just listId
,
n
odeId: Just nodeId
cpt {
mC
orpusId
,
mL
istId: Just listId
,
mN
odeId: Just nodeId
, session } _ = do
let session' = R.createContext session
pure $ D.documentLayout { listId
,
c
orpusId
,
mC
orpusId
, nodeId
, session } []
, session
: session'
} []
src/Gargantext/Components/RangeSlider.purs
View file @
1b753ff9
...
...
@@ -23,11 +23,13 @@ import Effect.Uncurried (mkEffectFn1)
import Math as M
import Reactix as R
import Reactix.DOM.HTML as H
import Toestand as T
import Gargantext.Utils.Math (roundToMultiple)
import Gargantext.Utils.Range as Range
import Gargantext.Utils.Reactix as R2
here :: R2.Here
here = R2.here "Gargantext.Components.RangeSlider"
-- data Axis = X | Y
...
...
src/Gargantext/Components/Router.purs
View file @
1b753ff9
...
...
@@ -4,9 +4,12 @@ import Data.Array (fromFoldable)
import Data.Maybe (Maybe(..), maybe')
import Reactix as R
import Toestand as T
import Unsafe.Coerce (unsafeCoerce)
import Gargantext.Prelude
import Gargantext.Components.App.Data (Cursors, Views)
import Gargantext.AsyncTasks as GAT
import Gargantext.Components.App.Data (Cursors)
import Gargantext.Components.Footer (footer)
import Gargantext.Components.Forest (forestLayout, forestLayoutWithTopBar)
import Gargantext.Components.GraphExplorer (explorerLayout)
...
...
@@ -23,10 +26,12 @@ import Gargantext.Components.Nodes.Frame (frameLayout)
import Gargantext.Components.Nodes.Home (homeLayout)
import Gargantext.Components.Nodes.Lists as Lists
import Gargantext.Components.Nodes.Texts as Texts
import Gargantext.Components.SessionLoader (sessionWrapper)
import Gargantext.Components.SimpleLayout (simpleLayout)
import Gargantext.Config (defaultFrontends, defaultBackends, publicBackend)
import Gargantext.Routes (AppRoute(..))
import Gargantext.Types (NodeType(..))
import Gargantext.Routes as GR
import Gargantext.Types (CorpusId, ListId, NodeID, NodeType(..), SessionId(..))
import Gargantext.Utils.Reactix as R2
import Gargantext.Utils.Toestand as T2
...
...
@@ -34,43 +39,43 @@ here :: R2.Here
here = R2.here "Gargantext.Components.Router"
type Props = (
cursors ::
App.
Cursors
cursors :: Cursors
, tasks :: T.Cursor (Maybe GAT.Reductor)
, views :: App.Views
)
router :: R2.Leaf Props
router props = R.create
Compon
ent routerCpt props []
router props = R.create
Elem
ent routerCpt props []
routerCpt :: R.Component Props
routerCpt = here.component "root" cpt where
cpt props@{ cursors, views, tasks } _ = do
let session = R.createContext (unsafeCoerce {})
showLogin <- T.useLive
(T2.ne)
views.showLogin
showLogin <- T.useLive
T.unequal
views.showLogin
route <- T.useLive (T.changed notEq) views.route
if showLogin then login' cursors views
else case route of
Annuaire s n -> annuaire props s n
Corpus s n -> corpus props s n
CorpusDocument s c l n -> corpusDocument props s c l n
Dashboard s n -> dashboard props s n
Document s l n -> document props s l n
Folder s n -> corpus props s n
FolderPrivate s n -> corpus props s n
FolderPublic s n -> corpus props s n
FolderShared s n -> corpus props s n
Home -> home props
Lists s n -> lists props s n
Login -> login' cursors
PGraphExplorer s g -> graphExplorer props s g
RouteFile s n -> routeFile props s n
RouteFrameCalc s n -> routeFrame props s n NodeFrameCalc
RouteFrameCode s n -> routeFrame props s n NodeFrameNotebook
RouteFrameWrite s n -> routeFrame props s n NodeFrameWrite
Team s n -> team props s n
Texts s n -> texts props s n
UserPage s n -> user props s n
ContactPage s a n -> contact props s a n
GR.
Annuaire s n -> annuaire props s n
GR.
Corpus s n -> corpus props s n
GR.
CorpusDocument s c l n -> corpusDocument props s c l n
GR.
Dashboard s n -> dashboard props s n
GR.
Document s l n -> document props s l n
GR.
Folder s n -> corpus props s n
GR.
FolderPrivate s n -> corpus props s n
GR.
FolderPublic s n -> corpus props s n
GR.
FolderShared s n -> corpus props s n
GR.
Home -> home props
GR.
Lists s n -> lists props s n
GR.
Login -> login' cursors
GR.
PGraphExplorer s g -> graphExplorer props s g
GR.
RouteFile s n -> routeFile props s n
GR.
RouteFrameCalc s n -> routeFrame props s n NodeFrameCalc
GR.
RouteFrameCode s n -> routeFrame props s n NodeFrameNotebook
GR.
RouteFrameWrite s n -> routeFrame props s n NodeFrameWrite
GR.
Team s n -> team props s n
GR.
Texts s n -> texts props s n
GR.
UserPage s n -> user props s n
GR.
ContactPage s a n -> contact props s a n
forested :: Record Props -> Array R.Element -> R.Element
forested { tasks, views: { route, handed, sessions }
...
...
@@ -86,31 +91,31 @@ authed props@{ cursors: { session }, views: views@{ sessions }
sessionWrapper { sessionId, session, sessions, fallback: home props }
[ content, footer { session: views.session } ]
annuaire :: Record Props -> SessionId -> NodeI
d
-> R.Element
annuaire :: Record Props -> SessionId -> NodeI
D
-> R.Element
annuaire props@{ tasks, cursors, views: { session } } sessionId nodeId =
authed props sessionId $
forested props [ annuaireLayout { nodeId, frontends, session } ]
where frontends = defaultFrontends
corpus :: Record Props -> SessionId -> NodeI
d
-> R.Element
corpus :: Record Props -> SessionId -> NodeI
D
-> R.Element
corpus props@{ tasks, cursors, views } sessionId nodeId =
authed props sessionId $
forested props
[ corpusLayout { nodeId, session: views.session } ]
corpusDocument :: Record Props -> SessionId -> CorpusId -> ListId -> NodeI
d
-> R.Element
corpusDocument :: Record Props -> SessionId -> CorpusId -> ListId -> NodeI
D
-> R.Element
corpusDocument props@{ tasks, cursors, views } sessionId corpusId' listId nodeId =
authed props sessionId $
forested props
[ documentMainLayout { listId, nodeId, corpusId, sessionId, session } [] ]
[ documentMainLayout { listId, nodeId, corpusId, sessionId, session
: views.session
} [] ]
where corpusId = Just corpusId'
dashboard :: Record Props -> SessionId -> NodeI
d
-> R.Element
dashboard :: Record Props -> SessionId -> NodeI
D
-> R.Element
dashboard props@{ tasks, cursors, views: { session } } sessionId nodeId =
authed props sessionId $
forested props [ dashboardLayout { nodeId, session } [] ]
document :: Record Props -> SessionId -> ListId -> NodeI
d
-> R.Element
document :: Record Props -> SessionId -> ListId -> NodeI
D
-> R.Element
document props@{ tasks, cursors, views: { session } } sessionId listId nodeId =
authed props sessionId $
forested props
...
...
@@ -121,7 +126,7 @@ home :: Record Props -> R.Element
home props@{ cursors: { backend, showLogin }, views: { sessions } } =
forested props [ homeLayout { sessions, backend, showLogin, lang: LL_EN } ]
lists :: Record Props -> SessionId -> NodeI
d
-> R.Element
lists :: Record Props -> SessionId -> NodeI
D
-> R.Element
lists props@{ tasks
, cursors: { reloadForest, reloadRoot, session, showLogin }
, views: { backend, route, handed, sessions } } sessionId nodeId =
...
...
@@ -154,19 +159,19 @@ graphExplorer props@{ views: { backend, route, handed, session, sessions }
, handed, session, sessions, showLogin } ]
where frontends = defaultFrontends
routeFile :: Record Props -> SessionId -> NodeI
d
-> R.Element
routeFile :: Record Props -> SessionId -> NodeI
D
-> R.Element
routeFile props@{ views: { session } } sessionId nodeId =
authed props sessionId $ forested props [ fileLayout { nodeId, session } ]
routeFrame :: Record Props -> SessionId -> NodeI
d
-> NodeType -> R.Element
routeFrame
Type
props@{ views: { session } } sessionId nodeId nodeType =
routeFrame :: Record Props -> SessionId -> NodeI
D
-> NodeType -> R.Element
routeFrame props@{ views: { session } } sessionId nodeId nodeType =
authed props sessionId $ forested props [ frameLayout { nodeId, nodeType, session } ]
team :: Record Props -> SessionId -> NodeI
d
-> R.Element
team :: Record Props -> SessionId -> NodeI
D
-> R.Element
team props@{ tasks, cursors, views: { session } } sessionId nodeId =
authed props sessionId $ forested props [ corpusLayout { nodeId, session } ]
texts :: Record Props -> SessionId -> NodeI
d
-> R.Element
texts :: Record Props -> SessionId -> NodeI
D
-> R.Element
texts props@{ cursors: { backend, reloadForest, reloadRoot, showLogin }
, views: { route, handed, session, sessions }
, tasks } sessionId nodeId =
...
...
@@ -177,14 +182,14 @@ texts props@{ cursors: { backend, reloadForest, reloadRoot, showLogin }
, textsProps: { frontends, nodeId, session } }
[] where frontends = defaultFrontends
user :: Record Props -> SessionId -> NodeI
d
-> R.Element
user props@
props
sessionId nodeId =
authed
{ tasks, cursors: { reloadRoot }, views: { session } }
sessionId $
user :: Record Props -> SessionId -> NodeI
D
-> R.Element
user props@
{ cursors: { reloadRoot }, tasks, views }
sessionId nodeId =
authed
props
sessionId $
forested props
[ userLayout { tasks, nodeId, session, reloadRoot, frontends } ]
[ userLayout { tasks, nodeId, session
: views.session
, reloadRoot, frontends } ]
where frontends = defaultFrontends
contact :: Record Props -> SessionId -> NodeI
d
-> R.Element
contact :: Record Props -> SessionId -> NodeI
D
-> R.Element
contact props@{ tasks, cursors: { reloadRoot } } sessionId annuaireId nodeId =
authed props sessionId $
forested props
...
...
src/Gargantext/Components/Search.purs
View file @
1b753ff9
...
...
@@ -10,6 +10,7 @@ import Gargantext.Prelude (class Eq, class Read, class Show)
import Gargantext.Components.Category.Types (Category)
import Gargantext.Utils.Argonaut (genericSumDecodeJson, genericSumEncodeJson, genericEnumDecodeJson, genericEnumEncodeJson)
import Gargantext.Utils.Toestand as T2
-- Example:
...
...
src/Gargantext/Components/Tab.purs
View file @
1b753ff9
...
...
@@ -12,8 +12,8 @@ import Gargantext.Utils.Reactix as R2
here :: R2.Here
here = R2.here "Gargantext.Components.Tab"
type TabsProps =
(
selected :: Int
type TabsProps =
(
selected :: Int
, tabs :: Array (Tuple String R.Element)
)
...
...
src/Gargantext/Components/Table.purs
View file @
1b753ff9
...
...
@@ -41,8 +41,8 @@ stateParams {pageSize, page, orderBy, searchType} = {offset, limit, orderBy, sea
limit = pageSizes2Int pageSize
offset = limit * (page - 1)
type TableHeaderLayoutProps =
(
afterCacheStateChange :: NT.CacheState -> Effect Unit
type TableHeaderLayoutProps =
(
afterCacheStateChange :: NT.CacheState -> Effect Unit
, cacheState :: R.State NT.CacheState
, date :: String
, desc :: String
...
...
src/Gargantext/Components/TopBar.purs
View file @
1b753ff9
...
...
@@ -13,6 +13,7 @@ import Gargantext.Prelude
import Gargantext.Components.Themes (themeSwitcher, defaultTheme, allThemes)
import Gargantext.Types (Handed(..), reverseHanded)
import Gargantext.Utils.Reactix as R2
import Gargantext.Utils.Toestand as T2
here :: R2.Here
here = R2.here "Gargantext.Components.TopBar"
...
...
@@ -248,6 +249,6 @@ handedChooserCpt = here.component "handedChooser" cpt
handedClass LeftHanded = "fa fa-hand-o-left"
handedClass RightHanded = "fa fa-hand-o-right"
onClick handed = T
.modify
(\h -> case h of
onClick handed = T
2.modify_
(\h -> case h of
LeftHanded -> RightHanded
RightHanded -> LeftHanded) handed
src/Gargantext/Hooks.purs
View file @
1b753ff9
...
...
@@ -6,11 +6,13 @@ import Routing.Match (Match)
import Routing.Hash (matches)
import Toestand as T
import Gargantext.Utils.Toestand as T2
-- | Sets up the hash router so it writes the route to the given cell.
-- | Note: if it gets sent to an unrecognised url, it will quietly
-- | drop the change.
useHashRouter :: forall r c. T.Write c r => Match r -> c -> R.Hooks Unit
useHashRouter routes cell = R.useEffectOnce $ matches routes h where
h _old new =
void $ T.write
new cell
h _old new =
T2.write_
new cell
-- useSession cell =
src/Gargantext/Hooks/Sigmax.purs
View file @
1b753ff9
...
...
@@ -22,10 +22,12 @@ import Effect.Class.Console (error)
import Effect.Timer (TimeoutId, clearTimeout)
import FFI.Simple ((.=))
import Reactix as R
import Toestand as T
import Gargantext.Hooks.Sigmax.Sigma as Sigma
import Gargantext.Hooks.Sigmax.Types as ST
import Gargantext.Utils.Reactix as R2
import Gargantext.Utils.Toestand as T2
type Sigma =
{ sigma :: R.Ref (Maybe Sigma.Sigma)
...
...
@@ -112,9 +114,10 @@ dependOnContainer container notFoundMsg f = do
-- | pausing can be done not only via buttons but also from the initial
-- | setTimer.
--handleForceAtlasPause sigmaRef (toggled /\ setToggled) mFAPauseRef = do
handleForceAtlas2Pause :: R.Ref Sigma ->
R.State
ST.ForceAtlasState -> R.Ref (Maybe TimeoutId) -> Effect Unit
handleForceAtlas2Pause sigmaRef
(toggled /\ setToggled)
mFAPauseRef = do
handleForceAtlas2Pause :: R.Ref Sigma ->
T.Cursor
ST.ForceAtlasState -> R.Ref (Maybe TimeoutId) -> Effect Unit
handleForceAtlas2Pause sigmaRef
forceAtlasState
mFAPauseRef = do
let sigma = R.readRef sigmaRef
toggled <- T.read forceAtlasState
dependOnSigma sigma "[handleForceAtlas2Pause] sigma: Nothing" $ \s -> do
--log2 "[handleForceAtlas2Pause] mSigma: Just " s
--log2 "[handleForceAtlas2Pause] toggled: " toggled
...
...
@@ -189,15 +192,15 @@ multiSelectUpdate new selected = foldl fld selected new
Set.insert item selectedAcc
bindSelectedNodesClick :: Sigma.Sigma ->
R.State
ST.NodeIds -> R.Ref Boolean -> Effect Unit
bindSelectedNodesClick sigma
(_ /\ setNodeIds)
multiSelectEnabledRef =
bindSelectedNodesClick :: Sigma.Sigma ->
T.Cursor
ST.NodeIds -> R.Ref Boolean -> Effect Unit
bindSelectedNodesClick sigma
selectedNodeIds
multiSelectEnabledRef =
Sigma.bindClickNodes sigma $ \nodes -> do
let multiSelectEnabled = R.readRef multiSelectEnabledRef
let nodeIds = Set.fromFoldable $ map _.id nodes
if multiSelectEnabled then
setNodeIds $ multiSelectUpdate n
odeIds
T2.modify_ (multiSelectUpdate nodeIds) selectedN
odeIds
else
setNodeIds $ const n
odeIds
T2.write_ nodeIds selectedN
odeIds
bindSelectedEdgesClick :: R.Ref Sigma -> R.State ST.EdgeIds -> Effect Unit
bindSelectedEdgesClick sigmaRef (_ /\ setEdgeIds) =
...
...
src/Gargantext/Sessions.purs
View file @
1b753ff9
...
...
@@ -34,12 +34,12 @@ import Gargantext.Components.Nodes.Lists.Types as NT
import Gargantext.Config.REST as REST
import Gargantext.Ends (class ToUrl, Backend, toUrl)
import Gargantext.Utils.Reactix (getls)
import Gargantext.Utils.Toestand as T2
load :: forall c. T.Write c Sessions => c -> Effect Sessions
load cell = do
sessions <- loadSessions
_ <- T.write sessions cell
pure sessions
T.write sessions cell
change
:: forall c
...
...
src/Gargantext/Utils/Range.purs
View file @
1b753ff9
...
...
@@ -16,6 +16,9 @@ instance closedRange :: Ord t => Range (Closed t) t where
clamp (Closed r) = max r.min <<< min r.max
within (Closed r) v = (v <= r.max) && (v >= r.min)
instance eqRange :: Eq t => Eq (Closed t) where
eq (Closed r1) (Closed r2) = (r1.min == r2.min) && (r1.max == r2.max)
type NumberRange = Closed Number
range :: NumberRange -> Number
...
...
src/Gargantext/Utils/Reload.purs
View file @
1b753ff9
...
...
@@ -8,6 +8,8 @@ import Effect (Effect)
import Reactix as R
import Toestand as T
import Gargantext.Utils.Toestand as T2
type Reload = Int
type ReloadS = R.State Reload
type ReloadSRef = R.Ref
...
...
@@ -19,9 +21,7 @@ bump :: ReloadS -> Effect Unit
bump (_ /\ setReload) = setReload (_ + 1)
bumpCursor :: T.Cursor Reload -> Effect Unit
bumpCursor c = do
_ <- T.modify (_ + 1) c
pure unit
bumpCursor c = T2.modify_ (_ + 1) c
value :: ReloadS -> Reload
value (val /\ _) = val
...
...
src/Gargantext/Utils/Toestand.purs
View file @
1b753ff9
...
...
@@ -2,6 +2,7 @@ module Gargantext.Utils.Toestand
( class Reloadable, reload
, Reload, newReload, InitReload(..), ready
, useCursed, useIdentityCursor, useMemberCursor
, write_, modify_
) where
import Prelude (class Ord, Unit, bind, identity, pure, unit, void, ($), (+), (>>=))
...
...
@@ -22,10 +23,10 @@ newReload :: Reload
newReload = 0
instance reloadableCellReload :: Reloadable (T.Cell Int) where
reload cell =
void $ T.modify
(_ + 1) cell
reload cell =
modify_
(_ + 1) cell
instance reloadableCursorReload :: Reloadable (T.Cursor Int) where
reload cell =
void $ T.modify
(_ + 1) cell
reload cell =
modify_
(_ + 1) cell
instance reloadableInitReloadCell :: Reloadable (c Reload) => Reloadable (T.Cell (InitReload c)) where
reload cell = do
...
...
@@ -51,7 +52,7 @@ ready :: forall cell c. T.ReadWrite cell (InitReload c) => T.ReadWrite (c Reload
ready cell with = do
val <- T.read cell
case val of
Init ->
void $ T.write
(Ready with) cell
Init ->
write_
(Ready with) cell
Ready _ -> pure unit
-- | Turns a Cell into a Cursor.
...
...
@@ -74,3 +75,9 @@ useMemberCursor val cell = T.useCursor (Set.member val) (toggleSet val) cell
toggleSet :: forall s. Ord s => s -> Boolean -> Set s -> Set s
toggleSet val true set = Set.insert val set
toggleSet val false set = Set.delete val set
modify_ :: forall cell val. T.ReadWrite cell val => (val -> val) -> cell -> Effect Unit
modify_ f cell = void $ T.modify f cell
write_ :: forall cell val. T.Write cell val => val -> cell -> Effect Unit
write_ val cell = void $ T.write val cell
test/Gargantext/Utils/Spec.purs
View file @
1b753ff9
module Gargantext.Utils.Spec where
import Prelude
import Data.Argonaut as Argonaut
import Data.Argonaut.Decode.Error (JsonDecodeError)
import Data.Either (Either(..), isLeft)
import Data.Generic.Rep (class Generic)
import Data.Generic.Rep.Show (genericShow)
import Test.Spec (Spec, describe, it)
import Test.Spec.Assertions (shouldEqual)
import Gargantext.Prelude
import Gargantext.Utils as GU
import Gargantext.Utils.Argonaut (genericEnumDecodeJson, genericEnumEncodeJson, genericSumDecodeJson, genericSumEncodeJson)
import Gargantext.Utils.Crypto as Crypto
import Gargantext.Utils.Math as GUM
import Test.Spec (Spec, describe, it)
import Test.Spec.Assertions (shouldEqual)
data Fruit
= Boat { hi :: Int }
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment