Texts.purs 16.8 KB
Newer Older
1
module Gargantext.Components.Nodes.Texts where
2

arturo's avatar
arturo committed
3 4
import Gargantext.Prelude

5
import Data.Generic.Rep (class Generic)
6
import Data.Maybe (Maybe(..))
7
import Data.Show.Generic (genericShow)
8
import Data.Tuple.Nested ((/\))
9
import Effect (Effect)
10
import Effect.Aff (launchAff_)
arturo's avatar
arturo committed
11
import Gargantext.Components.App.Store (Boxes)
12
import Gargantext.Components.Charts.Options.ECharts (dispatchAction)
arturo's avatar
arturo committed
13
import Gargantext.Components.Charts.Options.Type (EChartsInstance, EChartActionData)
14
import Gargantext.Components.DocsTable as DT
15
import Gargantext.Components.DocsTable.Types (Year)
16
import Gargantext.Components.NgramsTable.Loader (clearCache)
17
import Gargantext.Components.Node (NodePoly(..))
18
import Gargantext.Components.Nodes.Corpus (loadCorpusWithChild)
19
import Gargantext.Components.Nodes.Corpus.Chart.Histo (histo)
20
import Gargantext.Components.Nodes.Corpus.Chart.Types as CTypes
21
import Gargantext.Components.Nodes.Corpus.Document as D
22
import Gargantext.Components.Nodes.Corpus.Types (CorpusData)
23 24
import Gargantext.Components.Nodes.Lists.Types as LT
import Gargantext.Components.Nodes.Texts.Types as TT
arturo's avatar
arturo committed
25
import Gargantext.Components.Reload (textsReloadContext)
26
import Gargantext.Components.Tab as Tab
27
import Gargantext.Components.Table as Table
28
import Gargantext.Config.REST (logRESTError)
James Laver's avatar
James Laver committed
29
import Gargantext.Ends (Frontends)
30
import Gargantext.Hooks.Loader (useLoader)
31
import Gargantext.Sessions (WithSession, Session, getCacheState)
32
import Gargantext.Types (CTabNgramType(..), ListId, NodeID, SidePanelState(..), TabSubType(..), TabType(..))
33
import Gargantext.Utils.Reactix as R2
arturo's avatar
arturo committed
34
import Gargantext.Utils.Toestand as T2
35 36 37
import Reactix as R
import Reactix.DOM.HTML as H
import Toestand as T
38

James Laver's avatar
James Laver committed
39 40
here :: R2.Here
here = R2.here "Gargantext.Components.Nodes.Texts"
41

42
--------------------------------------------------------
43 44


45
type CommonPropsNoSession =
46 47 48
  ( boxes     :: Boxes
  , frontends :: Frontends
  , nodeId    :: NodeID
49 50
  )

51
type Props = WithSession CommonPropsNoSession
52

James Laver's avatar
James Laver committed
53

54 55
textsLayout :: R2.Component Props
textsLayout = R.createElement textsLayoutCpt
56
textsLayoutCpt :: R.Component Props
James Laver's avatar
James Laver committed
57
textsLayoutCpt = here.component "textsLayout" cpt where
58
  cpt { boxes, frontends, nodeId, session } children = do
arturo's avatar
arturo committed
59 60 61 62 63 64 65 66 67 68 69 70 71 72

    _ /\ reloadBox <- R2.useBox' T2.newReload

    pure $
      R.provideContext textsReloadContext (Just reloadBox)
      [
        textsLayoutWithKey
          { key
          , boxes
          , frontends
          , nodeId
          , session } children
      ]

73
      where
74 75 76 77
        key = show nodeId
        -- key = show sid <> "-" <> show nodeId
        --   where
        --     sid = sessionId session
78 79

type KeyProps = (
80 81 82 83 84
    key       :: String
  , boxes     :: Boxes
  , frontends :: Frontends
  , nodeId    :: NodeID
  , session   :: Session
85
  )
86

87 88
textsLayoutWithKey :: R2.Component KeyProps
textsLayoutWithKey = R.createElement textsLayoutWithKeyCpt
89
textsLayoutWithKeyCpt :: R.Component KeyProps
James Laver's avatar
James Laver committed
90
textsLayoutWithKeyCpt = here.component "textsLayoutWithKey" cpt
91
  where
92
    cpt { boxes: boxes@{ sidePanelTexts }
93 94
        , frontends
        , nodeId
95
        , session } _children = do
96
      cacheState <- T.useBox $ getCacheState LT.CacheOff session nodeId
97 98
      cacheState' <- T.useLive T.unequal cacheState

99 100 101 102
      yearFilter <- T.useBox (Nothing :: Maybe Year)

      eChartsInstance <- T.useBox (Nothing :: Maybe EChartsInstance)

103 104
      R.useEffectOnce' $ do
        T.listen (\{ new } -> afterCacheStateChange new) cacheState
105

106 107 108 109
      useLoader { errorHandler
                , loader: loadCorpusWithChild
                , path: { nodeId, session }
                , render: \corpusData@{ corpusId, corpusNode } -> do
110
                    let NodePoly { name, date, hyperdata } = corpusNode
111 112

                    R.fragment
arturo's avatar
arturo committed
113
                      [ Table.tableHeaderWithRenameLayout {
114
                          cacheState
115
                        , name
116 117 118 119 120
                        , date
                        , hyperdata
                        , nodeId: corpusId
                        , session
                        , key: "textsLayoutWithKey-" <> (show cacheState') } []
121 122
                      , tabs { boxes
                             , cacheState
123 124
                             , corpusData
                             , corpusId
125
                             , eChartsInstance
126 127
                             , frontends
                             , session
128
                             , sidePanel: sidePanelTexts
129 130 131
                             , yearFilter
                             }
                      ] }
132
      where
133
        errorHandler = logRESTError here "[textsLayoutWithKey]"
134 135
        afterCacheStateChange cacheState = do
          launchAff_ $ clearCache unit
136 137 138
          -- TODO
          --sessionUpdate $ setCacheState session nodeId cacheState
          --_ <- setCacheState session nodeId cacheState
139 140 141

data Mode = MoreLikeFav | MoreLikeTrash

142
derive instance Generic Mode _
143

144
instance Show Mode where
145 146
  show = genericShow

147
derive instance Eq Mode
148 149 150 151 152

modeTabType :: Mode -> CTabNgramType
modeTabType MoreLikeFav    = CTabAuthors  -- TODO
modeTabType MoreLikeTrash  = CTabSources  -- TODO

James Laver's avatar
James Laver committed
153
type TabsProps =
154 155
  ( boxes           :: Boxes
  , cacheState      :: T.Box LT.CacheState
156 157
  , corpusData      :: CorpusData
  , corpusId        :: NodeID
158
  , eChartsInstance :: T.Box (Maybe EChartsInstance)
159 160 161 162
  , frontends       :: Frontends
  , session         :: Session
  , sidePanel       :: T.Box (Maybe (Record TT.SidePanel))
  , yearFilter      :: T.Box (Maybe Year)
163
  )
164 165 166 167

tabs :: Record TabsProps -> R.Element
tabs props = R.createElement tabsCpt props []
tabsCpt :: R.Component TabsProps
168
tabsCpt = here.component "tabs" cpt
169
  where
170 171
    cpt { boxes
        , cacheState
172 173 174 175 176 177 178
        , corpusId
        , corpusData
        , eChartsInstance
        , frontends
        , session
        , sidePanel
        , yearFilter } _ = do
179 180 181 182 183 184 185 186 187 188 189 190 191 192

      let
        path = initialPath

        onInit = Just \i -> T.write_ (Just i) eChartsInstance

        onClick = Just \opts@{ name } -> do
          T.write_ (Just name) yearFilter
          T.read eChartsInstance >>= case _ of
            Nothing -> pure unit
            Just i  -> do
              -- @XXX due to lack of support for "echart.select" action,
              --      have to manually rely on a set/unset selection
              --      targeting the "echart.emphasis" action
arturo's avatar
arturo committed
193 194 195 196 197 198 199 200 201 202
              let
                opts' :: Record EChartActionData
                opts' =
                  { dataIndex   : opts.dataIndex
                  , name        : opts.name
                  , seriesId    : opts.seriesId
                  , seriesIndex : opts.seriesIndex
                  , seriesName  : opts.seriesName
                  , type        : "highlight"
                  }
203
              dispatchAction i { type: "downplay" }
arturo's avatar
arturo committed
204
              dispatchAction i opts'
205

206 207
      activeTab <- T.useBox 0

208 209
      chartReload <- T.useBox T2.newReload

210
      pure $ Tab.tabs {
211
          activeTab
212 213
        , tabs: [
            "Documents"       /\ R.fragment [
214 215
                histoRender { boxes, path, onClick, onInit, reload: chartReload, session } []
              , docView' path chartReload TabDocs
216
              ]
217
          , "Trash"           /\ docView' path chartReload TabTrash
218 219
          -- , "More like fav"   /\ docView' path TabMoreLikeFav
          -- , "More like trash" /\ docView' path TabMoreLikeTrash
220 221 222
          ]
        }

223
      where
224 225 226 227
        initialPath = { corpusId
                      , listId: corpusData.defaultListId
                      , limit: Nothing
                      , tabType: TabCorpus TabDocs }
228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254
        docView' path chartReload tabType = docView { boxes
                                                    , cacheState
                                                    , chartReload
                                                    , corpusData
                                                    , corpusId
                                                    , frontends
                                                    , listId: path.listId
                                                      -- , path
                                                    , session
                                                    , tabType
                                                    , sidePanel
                                                    , yearFilter
                                                    } []

type HistoProps =
  ( reload  :: T2.ReloadS
  | CTypes.Props
  )

histoRender :: R2.Component HistoProps
histoRender = R.createElement histoRenderCpt
histoRenderCpt :: R.Component HistoProps
histoRenderCpt = here.component "histoRender" cpt where
  cpt { boxes, path, onClick, onInit, reload, session } _ = do
    reload' <- T.useLive T.unequal reload

    pure $ histo { boxes, path, onClick, onInit, session }
255

256
type DocViewProps a =
257 258 259 260 261 262 263 264 265 266 267 268
  ( boxes       :: Boxes
  , cacheState  :: T.Box LT.CacheState
  , chartReload :: T2.ReloadS
  , corpusData  :: CorpusData
  , corpusId    :: NodeID
  , frontends   :: Frontends
  , listId      :: ListId
  -- , path     :: Record DT.Path
  , session     :: Session
  , tabType     :: TabSubType a
  , sidePanel   :: T.Box (Maybe (Record TT.SidePanel))
  , yearFilter  :: T.Box (Maybe Year)
269
  )
270

271 272
docView :: forall a. R2.Component (DocViewProps a)
docView = R.createElement docViewCpt
273
docViewCpt :: forall a. R.Component (DocViewProps a)
274
docViewCpt = here.component "docView" cpt
275
  where
276 277 278 279
    cpt props _children = do
      pure $ DT.docViewLayout $ docViewLayoutRec props

-- docViewLayoutRec :: forall a. DocViewProps a -> Record DT.LayoutProps
280 281
docViewLayoutRec { boxes
                 , cacheState
282
                 , chartReload
283 284
                 , corpusId
                 , frontends
285
                 , listId
286 287
                 , session
                 , tabType: TabDocs
288
                 , sidePanel
289 290
                 , yearFilter
                 } =
291 292
  { boxes
  , cacheState
293
  , chart  : H.div {} []
294
  , chartReload
295
  , frontends
296
  , listId
297
  , mCorpusId: Just corpusId
298 299 300
  , nodeId: corpusId
    -- ^ TODO merge nodeId and corpusId in DT
  , session
301
  , showSearch: true
302
  , sidePanel
303 304
  , tabType: TabCorpus TabDocs
  , totalRecords: 4737
305
  , yearFilter
306
  }
307 308
docViewLayoutRec { boxes
                 , cacheState
309
                 , chartReload
310 311
                 , corpusId
                 , frontends
312
                 , listId
313 314
                 , session
                 , tabType: TabMoreLikeFav
315
                 , sidePanel
316 317
                 , yearFilter
                 } =
318 319
  { boxes
  , cacheState
320
  , chart  : H.div {} []
321
  , chartReload
322
  , frontends
323
  , listId
324
  , mCorpusId: Just corpusId
325 326 327
  , nodeId: corpusId
    -- ^ TODO merge nodeId and corpusId in DT
  , session
328
  , showSearch: false
329
  , sidePanel
330 331
  , tabType: TabCorpus TabMoreLikeFav
  , totalRecords: 4737
332
  , yearFilter
333
  }
334 335
docViewLayoutRec { boxes
                 , cacheState
336
                 , chartReload
337 338
                 , corpusId
                 , frontends
339
                 , listId
340 341
                 , session
                 , tabType: TabMoreLikeTrash
342
                 , sidePanel
343 344
                 , yearFilter
                 } =
345 346
  { boxes
  , cacheState
347
  , chart  : H.div {} []
348
  , chartReload
349
  , frontends
350
  , listId
351
  , mCorpusId: Just corpusId
352 353 354
  , nodeId: corpusId
  -- ^ TODO merge nodeId and corpusId in DT
  , session
355
  , showSearch: false
356
  , sidePanel
357 358
  , tabType: TabCorpus TabMoreLikeTrash
  , totalRecords: 4737
359
  , yearFilter
360
  }
361 362
docViewLayoutRec { boxes
                 , cacheState
363
                 , chartReload
364 365
                 , corpusId
                 , frontends
366
                 , listId
367 368
                 , session
                 , tabType: TabTrash
369
                 , sidePanel
370 371
                 , yearFilter
                 } =
372 373
  { boxes
  , cacheState
374
  , chart  : H.div {} []
375
  , chartReload
376
  , frontends
377
  , listId
378
  , mCorpusId: Just corpusId
379 380 381
  , nodeId: corpusId
  -- ^ TODO merge nodeId and corpusId in DT
  , session
382
  , showSearch: true
383
  , sidePanel
384 385
  , tabType: TabCorpus TabTrash
  , totalRecords: 4737
386
  , yearFilter
387
  }
388
-- DUMMY
389 390
docViewLayoutRec { boxes
                 , cacheState
391
                 , chartReload
392 393
                 , corpusId
                 , frontends
394
                 , listId
395
                 , session
396
                 , sidePanel
397
                 , tabType
398 399
                 , yearFilter
                 } =
400 401
  { boxes
  , cacheState
402
  , chart  : H.div {} []
403
  , chartReload
404
  , frontends
405
  , listId
406
  , mCorpusId: Just corpusId
407 408 409
  , nodeId: corpusId
  -- ^ TODO merge nodeId and corpusId in DT
  , session
410
  , showSearch: true
411
  , sidePanel
412 413
  , tabType: TabCorpus TabTrash
  , totalRecords: 4737
414
  , yearFilter
415
  }
416 417 418 419


--------------------------------------------------------
type SidePanelProps = (
420 421 422
    boxes     :: Boxes
  , session   :: Session
  , sidePanel :: T.Box (Maybe (Record TT.SidePanel))
423 424
  )

425 426 427 428
textsSidePanel :: R2.Component SidePanelProps
textsSidePanel = R.createElement textsSidePanelCpt
textsSidePanelCpt :: R.Component SidePanelProps
textsSidePanelCpt = here.component "sidePanel" cpt
429
  where
430 431 432
    cpt { boxes: { sidePanelState }
        , session
        , sidePanel } _ = do
433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456

      sidePanelState' <- T.useLive T.unequal sidePanelState
      sidePanel' <- T.useLive T.unequal sidePanel

      -- R.useEffect' $ do
      --   let toggleSidePanel' _  = snd sidePanelState toggleSidePanelState
      --       triggerSidePanel' _ = snd sidePanelState $ const Opened
      --   R2.setTrigger toggleSidePanel  toggleSidePanel'
      --   R2.setTrigger triggerSidePanel triggerSidePanel'

      -- (mCorpusId /\ setMCorpusId) <- R.useState' Nothing
      -- (mListId /\ setMListId) <- R.useState' Nothing
      -- (mNodeId /\ setMNodeId) <- R.useState' Nothing

      -- R.useEffect3 mCorpusId mListId mNodeId $ do
      --   if mCorpusId == Just corpusId && mListId == Just listId && mNodeId == Just nodeId && mCurrentDocId == Just nodeId then do
      --     T.modify_ (\sp -> sp { mCurrentDocId = Nothing }) sidePanel
      --   else do
      --     T.modify_ (\sp -> sp { mCorpusId = Just corpusId
      --                         , mCurrentDocId = Just nodeId
      --                         , mListId = Just listId
      --                         , mNodeId = Just nodeId }) sidePanel
        -- let trigger :: Record TriggerAnnotatedDocIdChangeParams -> Effect Unit
        --     trigger { corpusId, listId, nodeId } = do
457 458 459
              -- log2 "[sidePanel trigger] trigger corpusId change" corpusId
              -- log2 "[sidePanel trigger] trigger listId change" listId
              -- log2 "[sidePanel trigger] trigger nodeId change" nodeId
460 461 462 463 464 465 466 467 468 469 470 471 472 473
              -- if mCorpusId == Just corpusId && mListId == Just listId && mNodeId == Just nodeId && mCurrentDocId == Just nodeId then do
                -- R.setRef currentDocIdRef Nothing
                -- T.modify_ (\sp -> sp { mCurrentDocId = Nothing }) sidePanel
                -- R2.callTrigger toggleSidePanel unit
              -- else do
                -- setMCorpusId $ const $ Just corpusId
                -- setMListId $ const $ Just listId
                -- setMNodeId $ const $ Just nodeId
                -- R.setRef currentDocIdRef $ Just nodeId
                -- R2.callTrigger triggerSidePanel unit
                -- T.modify_ (\sp -> sp { mCorpusId = Just corpusId
                --                     , mCurrentDocId = Just nodeId
                --                     , mListId = Just listId
                --                     , mNodeId = Just nodeId }) sidePanel
474
        -- log2 "[sidePanel] trigger" trigger
475 476
        -- R2.setTrigger triggerAnnotatedDocIdChange trigger
        -- pure unit
477

478 479 480
        -- pure $ do
        --   -- log "[sidePanel] clearing triggerAnnotatedDocIdChange"
        --   R2.clearTrigger triggerAnnotatedDocIdChange
481

482
      let mainStyle = case sidePanelState' of
483 484 485
            Opened -> { display: "block" }
            _      -> { display: "none" }

486
      let closeSidePanel _ = do
487 488 489 490
            -- T.modify_ (\sp -> sp { mCurrentDocId = Nothing
            --                     , state = Closed }) sidePanel
            T.write_ Closed sidePanelState
            T.write_ Nothing sidePanel
491

492
      pure $ H.div { style: mainStyle } [
493 494
        H.div { className: "header" } [
          H.span { className: "btn btn-danger"
495
                 , on: { click: closeSidePanel } } [
496 497 498
            H.span { className: "fa fa-times" } []
          ]
        ]
499
      , sidePanelDocView { mSidePanel: sidePanel', session } []
500 501 502
      ]

type SidePanelDocView = (
503 504
    mSidePanel :: Maybe (Record TT.SidePanel)
  , session    :: Session
505 506 507 508 509
  )

sidePanelDocView :: R2.Component SidePanelDocView
sidePanelDocView = R.createElement sidePanelDocViewCpt
sidePanelDocViewCpt :: R.Component SidePanelDocView
510
sidePanelDocViewCpt = here.component "sidePanelDocView" cpt
511
  where
512
    cpt { mSidePanel: Nothing } _ = do
513
      pure $ H.div {} []
514
    cpt { mSidePanel: Just { corpusId, listId, nodeId }
515
        , session } _ = do
516
      pure $ D.documentLayout { listId
517
                              , mCorpusId: Just corpusId
518
                              , nodeId
519
                              , session } []