Unverified Commit 64b242fc authored by Nicolas Pouillard's avatar Nicolas Pouillard

Finish multi-node selection

Merge remote-tracking branch 'origin/multinode-test' into dev-selector
parents cf762e19 7a74bebd
......@@ -9,7 +9,7 @@ import Affjax.ResponseFormat (printResponseFormatError)
import Affjax.ResponseFormat as ResponseFormat
import Control.Monad.Cont.Trans (lift)
import Data.Argonaut (class DecodeJson, class EncodeJson, decodeJson, encodeJson, jsonEmptyObject, (.?), (:=), (~>))
import Data.Array (drop, take, (:), filter)
import Data.Array (drop, take, (:), filter, (!!))
import Data.Either (Either(..))
import Data.Foldable (intercalate)
import Data.Generic.Rep (class Generic)
......@@ -30,6 +30,7 @@ import Gargantext.Config (End(..), NodeType(..), OrderBy(..), Path(..), TabType,
import Gargantext.Config.REST (put, post, deleteWithBody)
import Gargantext.Components.Loader as Loader
import Gargantext.Components.Table as T
import Gargantext.Utils (toggleSet)
import Gargantext.Utils.DecodeMaybe ((.|))
import React.DOM (a, br', button, div, i, input, p, text, span)
import React.DOM.Props (_type, className, href, onClick, placeholder, style, checked, target)
......@@ -43,14 +44,19 @@ import Thermite (PerformAction, Render, Spec, defaultPerformAction, modifyState_
type NodeID = Int
type TotalRecords = Int
-- Example:
-- [["machine","learning"],["artificial","intelligence"]]
-- This searches for documents with "machine learning" or "artificial intelligence"
type TextQuery = Array (Array String)
newtype SearchQuery = SearchQuery
{ query :: Array String
{ query :: TextQuery
, id :: Int
}
instance encodeJsonSearchQuery :: EncodeJson SearchQuery where
encodeJson (SearchQuery post)
= "query" := post.query
= "query" := post.query !! 0 -- TODO anoe
~> "corpus_id" := post.id
~> jsonEmptyObject
......@@ -64,7 +70,7 @@ instance decodeSearchResults :: DecodeJson SearchResults where
type Props =
{ nodeId :: Int
, query :: Array String
, query :: TextQuery
, totalRecords :: Int
, chart :: ReactElement
, container :: T.TableContainerProps -> Array ReactElement
......@@ -283,9 +289,9 @@ layoutDocviewGraph = simpleSpec performAction render
type PageParams = {nodeId :: Int, query :: Array String, params :: T.Params}
type PageParams = {nodeId :: Int, query :: TextQuery, params :: T.Params}
initialPageParams :: {nodeId :: Int, query :: Array String} -> PageParams
initialPageParams :: {nodeId :: Int, query :: TextQuery} -> PageParams
initialPageParams {nodeId, query} = {nodeId, query, params: T.initialParams}
loadPage :: PageParams -> Aff (Array DocumentsView)
......@@ -325,7 +331,7 @@ type PageLoaderProps row =
}
renderPage :: forall props path.
Render (Loader.State {nodeId :: Int, query :: Array String | path} (Array DocumentsView))
Render (Loader.State {nodeId :: Int, query :: TextQuery | path} (Array DocumentsView))
{ totalRecords :: Int
, dispatch :: Action -> Effect Unit
, deletionState :: State
......@@ -425,9 +431,3 @@ deleteFavorites nodeId = deleteWithBody (toUrl Back Node (Just nodeId) <> "/favo
deleteDocuments :: Int -> DeleteDocumentQuery -> Aff (Array Int)
deleteDocuments nodeId = deleteWithBody (toUrl Back Node (Just nodeId) <> "/documents")
-- TODO: not optimal but Data.Set lacks some function (Set.alter)
toggleSet :: forall a. Ord a => a -> Set a -> Set a
toggleSet a s
| Set.member a s = Set.delete a s
| otherwise = Set.insert a s
......@@ -9,17 +9,19 @@ import Affjax.ResponseFormat as ResponseFormat
import Control.Monad.Cont.Trans (lift)
import Data.Argonaut (class DecodeJson, class EncodeJson, decodeJson, jsonEmptyObject, (.?), (.??), (:=), (~>))
import Data.Argonaut (decodeJson)
import Data.Array (fold, length, mapWithIndex, (!!))
import Data.Array (fold, length, mapWithIndex, (!!), null)
import Data.Either (Either(..))
import Data.HTTP.Method (Method(..))
import Data.Int (fromString, toNumber)
import Data.Int as Int
import Data.Lens (Lens, Lens', over, (%~), (+~), (.~), (^.))
import Data.Lens (Lens, Lens', over, (%~), (+~), (.~), (^.), review)
import Data.Lens.Record (prop)
import Data.Maybe (Maybe(..), fromJust, fromMaybe, isNothing)
import Data.Newtype (class Newtype)
import Data.Number as Num
import Data.String (joinWith)
import Data.Set (Set)
import Data.Set as Set
import Data.Symbol (SProxy(..))
import Data.Traversable (for_)
import Effect (Effect)
......@@ -38,7 +40,7 @@ import Gargantext.Config.REST (get, post)
import Gargantext.Pages.Corpus.Graph.Tabs as GT
import Gargantext.Prelude (flip)
import Gargantext.Types (class Optional)
import Gargantext.Utils (getter)
import Gargantext.Utils (getter, toggleSet)
import Math (cos, sin)
import Partial.Unsafe (unsafePartial)
import React (ReactElement)
......@@ -51,7 +53,6 @@ import Web.HTML (window)
import Web.HTML.Window (localStorage)
import Web.Storage.Storage (getItem)
data Action
= LoadGraph Int
| SelectNode SelectedNode
......@@ -61,12 +62,21 @@ data Action
| ChangeLabelSize Number
| ChangeNodeSize Number
| DisplayEdges
| ToggleMultiNodeSelection
-- | Zoom Boolean
newtype SelectedNode = SelectedNode {id :: String, label :: String}
derive instance eqSelectedNode :: Eq SelectedNode
derive instance newtypeSelectedNode :: Newtype SelectedNode _
derive instance ordSelectedNode :: Ord SelectedNode
instance showSelectedNode :: Show SelectedNode where
show (SelectedNode node) = node.label
_multiNodeSelection :: forall s a. Lens' { multiNodeSelection :: a | s } a
_multiNodeSelection = prop (SProxy :: SProxy "multiNodeSelection")
-- _settings :: forall s t a b. Lens { settings :: a | s } { settings :: b | t } a b
_settings :: forall s a. Lens' { settings :: a | s } a
......@@ -106,7 +116,8 @@ newtype State = State
, filePath :: String
, sigmaGraphData :: Maybe SigmaGraphData
, legendData :: Array Legend
, selectedNode :: Maybe SelectedNode
, selectedNodes :: Set SelectedNode
, multiNodeSelection :: Boolean
, showSidePanel :: Boolean
, showControls :: Boolean
, showTree :: Boolean
......@@ -123,7 +134,8 @@ initialState = State
, filePath : ""
, sigmaGraphData : Nothing
, legendData : []
, selectedNode : Nothing
, selectedNodes : Set.empty
, multiNodeSelection : false
, showSidePanel : false
, showControls : false
, showTree : false
......@@ -154,8 +166,11 @@ performAction (LoadGraph fp) _ _ = void do
-- graph.
--modifyState \(State s) -> State s {graphData = resp, sigmaGraphData = Just $ convert resp, legendData = getLegendData resp}
performAction (SelectNode (SelectedNode node)) _ (State state) =
modifyState_ $ \(State s) -> State s {selectedNode = pure $ SelectedNode node}
performAction (SelectNode selectedNode@(SelectedNode node)) _ (State state) =
modifyState_ $ \(State s) ->
State s {selectedNodes = toggleSet selectedNode
(if s.multiNodeSelection then s.selectedNodes
else Set.empty) }
performAction (ShowSidePanel b) _ (State state) = void do
modifyState $ \(State s) -> State s {showSidePanel = b }
......@@ -181,6 +196,10 @@ performAction DisplayEdges _ _ =
modifyState_ $ \(State s) -> do
State $ ((_settings <<< _drawEdges) %~ not) s
performAction ToggleMultiNodeSelection _ _ =
modifyState_ $ \(State s) -> do
State $ s # _multiNodeSelection %~ not
--performAction (Zoom True) _ _ =
-- modifyState_ $ \() -> do
-- State $
......@@ -535,6 +554,15 @@ specOld = fold [treespec treeSpec, graphspec $ simpleSpec performAction render']
modCamera0 (const {ratio})
]
]
, li [className "col-me-2"]
[ span [] [text "MultiNode"]
, input
[ _type "checkbox"
, className "checkbox"
-- , checked
, onChange $ const $ d ToggleMultiNodeSelection
]
]
, li'
[ button [ className "btn btn-primary"
, onClick \_ -> pauseForceAtlas2
......@@ -569,7 +597,8 @@ specOld = fold [treespec treeSpec, graphspec $ simpleSpec performAction render']
, onClickNode : \e ->
unsafePerformEffect $ do
_ <- d $ ShowSidePanel true
_ <- d $ SelectNode $ SelectedNode {id : (unsafeCoerce e).data.node.id, label : (unsafeCoerce e).data.node.label}
let {id, label} = (unsafeCoerce e).data.node
_ <- d $ SelectNode $ SelectedNode {id, label}
pure unit
}
[ sigmaEnableWebGL
......@@ -664,10 +693,11 @@ specOld = fold [treespec treeSpec, graphspec $ simpleSpec performAction render']
[ div []
[ p [] []
, div [className "col-md-12"]
[ case st.selectedNode of
Just (SelectedNode {label}) ->
GT.tabsElt {query: words label, sides}
Nothing -> p [] []
[ let query = (\(SelectedNode {label}) -> words label) <$> Set.toUnfoldable st.selectedNodes in
if null query then
p [] []
else
GT.tabsElt {query, sides}
, p [] []
]
]
......
......@@ -6,7 +6,7 @@ import Data.List (fromFoldable)
import Data.Tuple (Tuple(..))
import Gargantext.Config (TabType(..), TabSubType(..))
import Gargantext.Components.GraphExplorer.Types (GraphSideCorpus(..))
import Gargantext.Components.FacetsTable as FT
import Gargantext.Components.FacetsTable (TextQuery, docViewSpec)
import Gargantext.Components.Table as T
import Gargantext.Components.Tab as Tab
import React (ReactElement, ReactClass, Children, createElement)
......@@ -14,23 +14,23 @@ import Thermite ( Spec, PerformAction, Render, _performAction, _render
, hideState, noState, cmapProps, simpleSpec, createClass
)
type Props = { query :: Array String, sides :: Array GraphSideCorpus }
type Props = { query :: TextQuery, sides :: Array GraphSideCorpus }
tabsElt :: Props -> ReactElement
tabsElt props = createElement tabsClass props []
-- TODO no need for Children here
tabsClass :: ReactClass { query :: Array String, sides :: Array GraphSideCorpus, children :: Children }
tabsClass :: ReactClass { query :: TextQuery, sides :: Array GraphSideCorpus, children :: Children }
tabsClass = createClass "GraphTabs" pureTabs (const {})
pureTabs :: Spec {} Props Void
pureTabs = hideState (const {activeTab: 0}) statefulTabs
tab :: forall props state. Array String -> GraphSideCorpus -> Tuple String (Spec state props Tab.Action)
tab :: forall props state. TextQuery -> GraphSideCorpus -> Tuple String (Spec state props Tab.Action)
tab query (GraphSideCorpus {corpusId: nodeId, corpusLabel}) =
Tuple corpusLabel $
cmapProps (const {nodeId, query, chart, totalRecords: 4736, container}) $
noState FT.docViewSpec
noState docViewSpec
where
-- TODO totalRecords: probably need to insert a corpusLoader.
chart = mempty
......
......@@ -3,6 +3,8 @@ module Gargantext.Utils where
import Prelude
import Data.Newtype (class Newtype, unwrap, wrap)
import Data.Set as Set
import Data.Set (Set)
setterv :: forall nt record field. Newtype nt record => (record -> field -> record) -> field -> nt -> nt
setterv fn v t = (setter (flip fn v) t)
......@@ -12,3 +14,9 @@ setter fn = wrap <<< fn <<< unwrap
getter :: forall record field nt. Newtype nt record => (record -> field) -> nt -> field
getter fn = fn <<< unwrap
-- TODO: not optimal but Data.Set lacks some function (Set.alter)
toggleSet :: forall a. Ord a => a -> Set a -> Set a
toggleSet a s
| Set.member a s = Set.delete a s
| otherwise = Set.insert a s
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