Unverified Commit ce5135f4 authored by Nicolas Pouillard's avatar Nicolas Pouillard

Merge branch 'ngrams-table' into delete-and-favorite-api

This is WIP in particular the missing function "dispatch2" in Documents.
parents 662c8d7b 8030266a
#!/bin/bash
rm -rf output bower_components node_modules
rm -rf .psc-package output bower_components node_modules
./build
module Gargantext.Components.Loader where
import Control.Monad.Cont.Trans (lift)
import Data.Maybe (Maybe(..))
import Data.Either (Either(..))
import Data.Traversable (traverse_)
import React as React
import React (ReactClass)
import React (ReactClass, Children)
import Gargantext.Prelude
import Effect.Aff (Aff, launchAff, launchAff_, makeAff, nonCanceler, killFiber)
import Effect.Exception (error)
import Effect (Effect)
import Effect.Aff (Aff)
type InnerProps a b =
{ path :: a
, loaded :: Maybe b
, children :: React.Children
import Thermite (Render, PerformAction, simpleSpec, modifyState_, createReactSpec)
data Action path = ForceReload | SetPath path
type InnerProps path loaded =
{ path :: path
, loaded :: Maybe loaded
, dispatch :: Action path -> Effect Unit
, children :: Children
}
type Props a b = { path :: a
, component :: ReactClass (InnerProps a b)
}
type PropsRow path loaded row =
( path :: path
, component :: ReactClass (InnerProps path loaded)
| row
)
type Props path loaded = Record (PropsRow path loaded (children :: Children))
type Props' path loaded = Record (PropsRow path loaded ())
type State path loaded = { currentPath :: path, loaded :: Maybe loaded }
createLoaderClass' :: forall path loaded props
. Eq path
=> String
-> (path -> Aff loaded)
-> Render (State path loaded) {path :: path | props} (Action path)
-> ReactClass { path :: path, children :: Children | props }
createLoaderClass' name loader render =
React.component name
(\this -> do
s <- spec this
pure { state: s.state
, render: s.render
, componentDidMount: dispatcher this ForceReload
})
where
initialState {path} = {currentPath: path, loaded: Nothing}
performAction :: PerformAction (State path loaded) {path :: path | props} (Action path)
performAction ForceReload _ {currentPath} = do
loaded <- lift $ loader currentPath
modifyState_ $ _ { loaded = Just loaded }
performAction (SetPath newPath) _ {currentPath} =
when (newPath /= currentPath) $ do
loaded <- lift $ loader newPath
modifyState_ $ _ { currentPath = newPath, loaded = Just loaded }
{spec, dispatcher} = createReactSpec (simpleSpec performAction render) initialState
createLoaderClass :: forall path loaded
. Eq path
=> String
-> (path -> Aff loaded)
-> ReactClass (Record (PropsRow path loaded (children :: Children)))
createLoaderClass name loader =
createLoaderClass' name loader render
where
render :: Render (State path loaded) (Props' path loaded) (Action path)
render dispatch {component} {currentPath, loaded} c =
[React.createElement component {path: currentPath, loaded, dispatch} c]
createLoaderClass :: forall a b
{-
createLoaderClass :: forall path loaded
. String
-> (a -> Aff b)
-> ReactClass (Props a b)
-> (path -> Aff loaded)
-> ReactClass (Props path loaded)
createLoaderClass name loader = React.component name mk
where
mk this =
......@@ -49,3 +102,4 @@ createLoaderClass name loader = React.component name mk
{loaded} <- React.getState this
pure $ React.createElement component {path, loaded} []
}
-}
module Gargantext.Components.Table where
import Control.Monad.Cont.Trans (lift)
import Data.Array (filter)
import Data.Maybe (Maybe(..), maybe)
import Data.Either (Either(..))
import Effect (Effect)
import Effect.Aff (Aff)
import React as React
import Effect.Class (liftEffect)
import React (ReactElement, ReactClass, Children, createElement)
import React.DOM (a, b, b', p, i, h3, hr, div, option, select, span, table, tbody, td, text, th, thead, tr)
import React.DOM.Props (className, href, onChange, onClick, scope, selected, value, style)
import Thermite (PerformAction, Render, Spec, modifyState, simpleSpec, createReactSpec, StateCoTransformer)
import Thermite (PerformAction, Render, Spec, modifyState_, simpleSpec, StateCoTransformer, createClass)
import Unsafe.Coerce (unsafeCoerce)
import Gargantext.Prelude
......@@ -29,7 +27,7 @@ type Rows = Array { row :: Array ReactElement
type OrderBy = Maybe (OrderByDirection ColumnName)
type LoadRows = { offset :: Int, limit :: Int, orderBy :: OrderBy } -> Aff Rows
type Params = { offset :: Int, limit :: Int, orderBy :: OrderBy }
newtype ColumnName = ColumnName String
......@@ -40,32 +38,34 @@ columnName (ColumnName c) = c
data OrderByDirection a = ASC a | DESC a
derive instance eqOrderByDirection :: Eq a => Eq (OrderByDirection a)
type Props' =
( colNames :: Array ColumnName
, totalRecords :: Int
, loadRows :: LoadRows
, setParams :: Params -> Effect Unit
, rows :: Rows
, container :: TableContainerProps -> Array ReactElement
)
type Props = Record Props'
type State =
{ rows :: Maybe Rows
, currentPage :: Int
{ currentPage :: Int
, pageSize :: PageSizes
, orderBy :: OrderBy
--, tree :: FTree
}
initialState :: State
initialState =
{ rows : Nothing
, currentPage : 1
{ currentPage : 1
, pageSize : PS10
, orderBy : Nothing
--, tree : exampleTree
}
initialParams :: Params
initialParams = stateParams initialState
data Action
= ChangePageSize PageSizes
| ChangePage Int
......@@ -118,9 +118,9 @@ tableSpec :: Spec State Props Action
tableSpec = simpleSpec performAction render
where
modifyStateAndReload :: (State -> State) -> Props -> State -> StateCoTransformer State Unit
modifyStateAndReload f {loadRows} state = do
void $ modifyState f
loadAndSetRows {loadRows} $ f state
modifyStateAndReload f {setParams} state = do
modifyState_ f
liftEffect $ setParams $ stateParams $ f state
performAction :: PerformAction State Props Action
performAction (ChangePageSize ps) =
......@@ -145,8 +145,8 @@ tableSpec = simpleSpec performAction render
_ -> [lnk (Just (ASC c)) (columnName c)]
render :: Render State Props Action
render dispatch {container, colNames, totalRecords}
{pageSize, currentPage, orderBy, rows} _ =
render dispatch {container, colNames, totalRecords, rows}
{pageSize, currentPage, orderBy} _ =
container
{ pageSizeControl: sizeDD pageSize dispatch
, pageSizeDescription: textDescription currentPage pageSize totalRecords
......@@ -154,10 +154,7 @@ tableSpec = simpleSpec performAction render
, tableHead:
tr [] (renderColHeader (dispatch <<< ChangeOrderBy) orderBy <$> colNames)
, tableBody:
map (tr [] <<< map (\c -> td [] [c]) <<< _.row)
(maybe [] identity rows)
-- TODO display a loading spinner when rows == Nothing
-- instead of an empty list of results.
map (tr [] <<< map (\c -> td [] [c]) <<< _.row) rows
}
where
ps = pageSizes2Int pageSize
......@@ -169,7 +166,7 @@ defaultContainer {title} props =
[ div [className "col-md-1"] [b [] [text title]]
, div [className "col-md-2"] [props.pageSizeControl]
, div [className "col-md-3"] [props.pageSizeDescription]
, div [className "col-md-3"] []
, div [className "col-md-3"] [props.paginationLinks]
]
, table [ className "table"]
[ thead [className "thead-dark"] [ props.tableHead ]
......@@ -177,26 +174,14 @@ defaultContainer {title} props =
]
]
loadAndSetRows :: {loadRows :: LoadRows} -> State -> StateCoTransformer State Unit
loadAndSetRows {loadRows} {pageSize, currentPage, orderBy} = do
let limit = pageSizes2Int pageSize
offset = limit * (currentPage - 1)
rows <- lift $ loadRows {offset, limit, orderBy}
void $ modifyState (_ { rows = Just rows })
stateParams :: State -> Params
stateParams {pageSize, currentPage, orderBy} = {offset, limit, orderBy}
where
limit = pageSizes2Int pageSize
offset = limit * (currentPage - 1)
tableClass :: ReactClass {children :: Children | Props'}
tableClass =
React.component "Table"
(\this -> do
{state, render} <- spec this
pure { state, render
, componentDidMount: do
{loadRows} <- React.getProps this
state' <- React.getState this
dispatcher' this $ loadAndSetRows {loadRows} state'
})
where
{ spec, dispatcher' } = createReactSpec tableSpec initialState
tableClass = createClass "Table" tableSpec (const initialState)
tableElt :: Props -> ReactElement
tableElt props = createElement tableClass props []
......@@ -220,10 +205,7 @@ textDescription currPage pageSize totalRecords
end = if end' > totalRecords then totalRecords else end'
effectLink :: Effect Unit -> String -> ReactElement
effectLink eff msg =
a [ href "javascript:void()"
, onClick (const eff)
] [text msg]
effectLink eff msg = a [onClick $ const eff] [text msg]
pagination :: ChangePageAction -> Int -> Int -> ReactElement
pagination changePage tp cp
......
......@@ -5,10 +5,12 @@ import Data.Lens (Prism', prism)
import Data.Either (Either(..))
import Data.Maybe (Maybe(..), maybe)
import React as React
import React (ReactClass, ReactElement)
import React (ReactClass, ReactElement, Children)
import React.DOM (a, br', div, input, p, text)
import React.DOM.Props (href)
import Effect (Effect)
import Effect.Aff (Aff)
import Effect.Class (liftEffect)
import Thermite ( Render, Spec
, createClass, simpleSpec, defaultPerformAction
)
......@@ -16,15 +18,17 @@ import Thermite ( Render, Spec
------------------------------------------------------------------------------
import Gargantext.Prelude
import Gargantext.Components.Loader as Loader
import Gargantext.Components.Loader (createLoaderClass)
import Gargantext.Components.Tab as Tab
import Gargantext.Components.Table as Table
import Gargantext.Components.Table as T
import Gargantext.Config (toUrl, NodeType(..), TabType(..), End(..))
import Gargantext.Config.REST (get)
import Gargantext.Pages.Annuaire.User.Contacts.Types (Contact(..), HyperData(..))
------------------------------------------------------------------------------
type Props = {path :: Int, loaded :: Maybe AnnuaireInfo }
type Props =
{ path :: Int
, loaded :: Maybe AnnuaireInfo
, dispatch :: Loader.Action Int -> Effect Unit }
data Action
= TabsA Tab.Action
......@@ -71,7 +75,7 @@ layout = simpleSpec defaultPerformAction render
render _ {annuaireId} _ _ =
[ annuaireLoader
{ path: annuaireId
, component: createClass "LoadedAnnuaire" loadedAnnuaireSpec {}
, component: createClass "LoadedAnnuaire" loadedAnnuaireSpec (const {})
} ]
loadedAnnuaireSpec :: Spec {} Props Void
......@@ -79,8 +83,8 @@ loadedAnnuaireSpec = simpleSpec defaultPerformAction render
where
render :: Render {} Props Void
render _ {loaded: Nothing} _ _ = []
render _ {path, loaded: Just (AnnuaireInfo {name, date})} _ _ =
Table.renderTableHeaderLayout
render _ {path: nodeId, loaded: Just (annuaireInfo@AnnuaireInfo {name, date})} _ _ =
T.renderTableHeaderLayout
{ title: name
, desc: name
, query: ""
......@@ -90,25 +94,54 @@ loadedAnnuaireSpec = simpleSpec defaultPerformAction render
[ p [] []
, div [] [ text " Filter ", input []]
, br'
, Table.tableElt
{ loadRows
, container: Table.defaultContainer { title: "title" } -- TODO
, colNames:
Table.ColumnName <$>
, pageLoader
{ path: initialPageParams nodeId
, annuaireInfo
}
]
type PageParams = {nodeId :: Int, params :: T.Params}
initialPageParams :: Int -> PageParams
initialPageParams nodeId = {nodeId, params: T.initialParams}
type PageLoaderProps =
{ path :: PageParams
, annuaireInfo :: AnnuaireInfo
}
renderPage :: forall props path.
Render (Loader.State {nodeId :: Int | path} AnnuaireTable)
{annuaireInfo :: AnnuaireInfo | props}
(Loader.Action PageParams)
renderPage _ _ {loaded: Nothing} _ = [] -- TODO loading spinner
renderPage dispatch {annuaireInfo}
{ currentPath: {nodeId}
, loaded: Just (AnnuaireTable {annuaireTable: res})
} _ =
[ T.tableElt
{ rows
, setParams: \params -> liftEffect $ dispatch (Loader.SetPath {nodeId, params})
, container: T.defaultContainer { title: "Annuaire" } -- TODO
, colNames:
T.ColumnName <$>
[ ""
, "Name"
, "Role"
, "Service"
, "Company"
]
, totalRecords: 47361 -- TODO
}
]
where
annuaireId = path
loadRows {offset, limit, orderBy} = do -- TODO use offset, limit, orderBy
(AnnuaireTable {annuaireTable: rows}) <- getTable annuaireId
pure $ (\c -> {row: renderContactCells c, delete: false}) <$> rows
, totalRecords: 47361 -- TODO
}
]
where
rows = (\c -> {row: renderContactCells c, delete: false}) <$> res
pageLoaderClass :: ReactClass { path :: PageParams, annuaireInfo :: AnnuaireInfo, children :: Children }
pageLoaderClass = Loader.createLoaderClass' "AnnuairePageLoader" loadPage renderPage
pageLoader :: PageLoaderProps -> ReactElement
pageLoader props = React.createElement pageLoaderClass props []
renderContactCells :: Contact -> Array ReactElement
renderContactCells (Contact { id, hyperdata : HyperData contact }) =
......@@ -168,15 +201,17 @@ instance decodeAnnuaireTable :: DecodeJson AnnuaireTable where
rows <- decodeJson json
pure $ AnnuaireTable { annuaireTable : rows}
------------------------------------------------------------------------
getTable :: Int -> Aff AnnuaireTable
getTable id = get $ toUrl Back (Tab TabDocs 0 10 Nothing) id
loadPage :: PageParams -> Aff AnnuaireTable
loadPage {nodeId, params} = get $ toUrl Back (Tab TabDocs 0 10 Nothing) nodeId
-- TODO Tab TabDocs is not the right API call
-- TODO params, see loadPage in Documents
getAnnuaireInfo :: Int -> Aff AnnuaireInfo
getAnnuaireInfo id = get $ toUrl Back Node id
------------------------------------------------------------------------------
annuaireLoaderClass :: ReactClass (Loader.Props Int AnnuaireInfo)
annuaireLoaderClass = createLoaderClass "AnnuaireLoader" getAnnuaireInfo
annuaireLoaderClass = Loader.createLoaderClass "AnnuaireLoader" getAnnuaireInfo
annuaireLoader :: Loader.Props Int AnnuaireInfo -> ReactElement
annuaireLoader = React.createLeafElement annuaireLoaderClass
annuaireLoader :: Loader.Props' Int AnnuaireInfo -> ReactElement
annuaireLoader props = React.createElement annuaireLoaderClass props []
......@@ -28,9 +28,9 @@ type Props = Tabs.Props
type State = { tabsView :: Tabs.State
}
initialState :: State
initialState = { tabsView : Tabs.initialState
}
initialState :: Props -> State
initialState _props =
{ tabsView : Tabs.initialState {} }
------------------------------------------------------------------------
_tabsView :: forall a b. Lens' { tabsView :: a | b } a
......@@ -87,5 +87,5 @@ getCorpus = get <<< toUrl Back Corpus
corpusLoaderClass :: ReactClass (Loader.Props Int (NodePoly CorpusInfo))
corpusLoaderClass = createLoaderClass "CorpusLoader" getCorpus
corpusLoader :: Loader.Props Int (NodePoly CorpusInfo) -> ReactElement
corpusLoader = React.createLeafElement corpusLoaderClass
corpusLoader :: Loader.Props' Int (NodePoly CorpusInfo) -> ReactElement
corpusLoader props = React.createElement corpusLoaderClass props []
......@@ -26,8 +26,8 @@ type State =
, inputValue :: String
}
initialState :: State
initialState =
initialState :: {} -> State
initialState {} =
{ document : Nothing
, inputValue : ""
}
......
......@@ -20,7 +20,7 @@ import Data.Void (Void)
import Data.Unit (Unit)
import Effect (Effect)
import Effect.Aff (Aff)
import React (ReactElement, ReactClass)
import React (ReactElement, ReactClass, Children)
import React as React
import React.DOM hiding (style, map)
import React.DOM.Props (_id, _type, checked, className, href, name, onChange, onClick, onInput, placeholder, scope, selected, style, value)
......@@ -38,8 +38,11 @@ import Gargantext.Pages.Corpus.Tabs.Types (CorpusInfo(..), PropsRow)
type Props = { mode :: Mode | PropsRow }
type Props' = { path :: Int
type PageParams = {nodeId :: Int, params :: T.Params}
type Props' = { path :: PageParams
, loaded :: Maybe NgramsTable
, dispatch :: Loader.Action PageParams -> Effect Unit
}
type NgramsTerm = String
......@@ -173,12 +176,13 @@ type State =
, termTypeFilter :: Maybe TermType -- Nothing means all
}
initialState :: State
initialState = { ngramsTablePatch: mempty
, searchQuery: ""
, termListFilter: Nothing
, termTypeFilter: Nothing
}
initialState :: forall props. props -> State
initialState _ =
{ ngramsTablePatch: mempty
, searchQuery: ""
, termListFilter: Nothing
, termTypeFilter: Nothing
}
data Action
= SetTermListItem NgramsTerm (Replace TermList)
......@@ -281,10 +285,13 @@ ngramsTableSpec' = simpleSpec performAction render
-- patch the root of the child to be equal to the root of the parent.
render :: Render State Props' Action
render dispatch {path: nodeId, loaded: initTable}
{ngramsTablePatch, searchQuery {- TODO more state -} } _ =
render dispatch { path: {nodeId}
, loaded: initTable
, dispatch: loaderDispatch }
{ ngramsTablePatch, searchQuery } _children =
[ T.tableElt
{ loadRows
{ rows
, setParams: \params -> loaderDispatch (Loader.SetPath {nodeId, params})
, container: tableContainer {searchQuery, dispatch}
, colNames:
T.ColumnName <$>
......@@ -293,37 +300,48 @@ ngramsTableSpec' = simpleSpec performAction render
, "Terms"
, "Occurences (nb)"
]
, totalRecords: 10 -- TODO
, totalRecords: 47361 -- TODO
}
]
where
loadRows {offset, limit, orderBy} =
case applyNgramsTablePatch ngramsTablePatch <$> initTable of
Nothing -> pure [] -- or an error
Just (NgramsTable table) ->
pure $ convertRow <$> Map.toUnfoldable (Map.filter isRoot table)
isRoot (NgramsElement e) = e.root == Nothing
convertRow (Tuple ngrams (NgramsElement { occurrences, list })) =
{ row:
let
setTermList Keep = do
logs "setTermList Keep"
pure unit
setTermList rep@(Replace {old,new}) = do
logs $ Tuple "setTermList" (Tuple old new)
dispatch $ SetTermListItem ngrams rep in
renderNgramsItem { ngrams, occurrences, termList: list, setTermList }
, delete: false
}
where
rows =
case applyNgramsTablePatch ngramsTablePatch <$> initTable of
Nothing -> [] -- or an error
Just (NgramsTable table) ->
convertRow <$> Map.toUnfoldable (Map.filter isRoot table)
isRoot (NgramsElement e) = e.root == Nothing
convertRow (Tuple ngrams (NgramsElement { occurrences, list })) =
{ row:
let
setTermList Keep = do
logs "setTermList Keep"
pure unit
setTermList rep@(Replace {old,new}) = do
logs $ Tuple "setTermList" (Tuple old new)
dispatch $ SetTermListItem ngrams rep in
renderNgramsItem { ngrams, occurrences, termList: list, setTermList }
, delete: false
}
initialPageParams :: Int -> PageParams
initialPageParams nodeId = {nodeId, params: T.initialParams}
type PageLoaderProps =
{ path :: PageParams
--, corpusInfo :: Maybe (NodePoly CorpusInfo)
}
getNgramsTable :: Int -> Aff NgramsTable
getNgramsTable = get <<< toUrl Back (Ngrams TabTerms Nothing)
ngramsLoaderClass :: ReactClass (Loader.Props Int NgramsTable)
ngramsLoaderClass = Loader.createLoaderClass "NgramsLoader" getNgramsTable
loadPage :: PageParams -> Aff NgramsTable
loadPage {nodeId} = getNgramsTable nodeId -- TODO this ignores params
ngramsLoaderClass :: ReactClass (Loader.Props PageParams NgramsTable)
ngramsLoaderClass = Loader.createLoaderClass "NgramsLoader" loadPage
ngramsLoader :: Loader.Props Int NgramsTable -> ReactElement
ngramsLoader = React.createLeafElement ngramsLoaderClass
ngramsLoader :: Loader.Props' PageParams NgramsTable -> ReactElement
ngramsLoader props = React.createElement ngramsLoaderClass props []
ngramsTableSpec :: Spec {} Props Void
ngramsTableSpec = simpleSpec defaultPerformAction render
......@@ -331,7 +349,7 @@ ngramsTableSpec = simpleSpec defaultPerformAction render
render :: Render {} Props Void
render _ {path: nodeId} _ _ =
-- TODO: ignored mode, ignored loaded: corpusInfo
[ ngramsLoader { path: nodeId
[ ngramsLoader { path: initialPageParams nodeId
, component: createClass "Layout" ngramsTableSpec' initialState
} ]
......
......@@ -15,8 +15,8 @@ import Gargantext.Components.Tab as Tab
import Thermite (Spec, focus, hideState, cmapProps)
pureTabs :: Spec {} Props Void
pureTabs = hideState initialState statefulTabs
-- pureTabs :: Spec {} Props Void
-- pureTabs = hideState initialState statefulTabs
statefulTabs :: Spec State Props Action
statefulTabs =
......@@ -32,7 +32,7 @@ docPageSpec = focus _doclens _docAction DV.layoutDocview
ngramsViewSpec :: {mode :: NV.Mode} -> Spec State Props Action
ngramsViewSpec {mode} =
cmapProps (\{loaded, path} -> {mode,loaded,path})
cmapProps (\{loaded, path, dispatch} -> {mode,loaded,path, dispatch})
(focus _ngramsView _NgramViewA NV.ngramsTableSpec)
authorPageSpec :: Spec State Props Action
......
......@@ -12,9 +12,8 @@ type State =
, activeTab :: Int
}
initialState :: State
initialState =
initialState :: {} -> State
initialState _ =
{ docsView :
{ documents : D.sampleData'
, deleteRows : false
......
......@@ -2,9 +2,11 @@ module Gargantext.Pages.Corpus.Tabs.Types where
import Data.Argonaut (class DecodeJson, decodeJson, (.?), (.??))
import Data.Maybe (Maybe(..))
import Effect (Effect)
--------------------------------------------------------
import Gargantext.Prelude
import Gargantext.Components.Node (NodePoly(..))
import Gargantext.Components.Loader as Loader
newtype CorpusInfo = CorpusInfo { title :: String
, desc :: String
......@@ -43,7 +45,11 @@ instance decodeCorpusInfo :: DecodeJson CorpusInfo where
pure $ CorpusInfo {title, desc, query, authors, chart, totalRecords}
-- TODO type Props = {nodeId :: Int, info :: Maybe (NodePoly CorpusInfo) }
type PropsRow = (path :: Int, loaded :: Maybe (NodePoly CorpusInfo))
type PropsRow =
( path :: Int
, loaded :: Maybe (NodePoly CorpusInfo)
, dispatch :: Loader.Action Int -> Effect Unit
)
type Props = Record PropsRow
-- TODO include Gargantext.Pages.Corpus.Tabs.States
......
......@@ -26,7 +26,7 @@ landingData FR = Fr.landingData
landingData EN = En.landingData
layoutLanding :: Lang -> Spec {} {} Void
layoutLanding = hideState (unwrap initialState)
layoutLanding = hideState (const $ unwrap initialState)
<<< focusState (re _Newtype)
<<< layoutLanding' <<< landingData
......
......@@ -36,7 +36,7 @@ initAppState =
, addCorpusState : AC.initialState
, searchState : S.initialState
, userPageState : C.initialState
, documentState : D.initialState
, documentState : D.initialState {}
, ntreeState : Tree.exampleTree
, search : ""
, showLogin : false
......
......@@ -24,7 +24,7 @@ setUnsafeComponentWillMount = unsafeSet "unsafeComponentWillMount"
main :: Effect Unit
main = do
case T.createReactSpec layoutSpec initAppState of
case T.createReactSpec layoutSpec (const initAppState) of
{ spec, dispatcher } -> void $ do
let setRouting this = void $ do
matches routing (routeHandler (dispatchAction (dispatcher this)))
......
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