Commit 4b90694c authored by arturo's avatar arturo

[graph] Doc Focus

* #375: rc5.x
parent 9961ac74
Pipeline #2750 failed with stage
in 0 seconds
......@@ -6154,6 +6154,59 @@ h3 {
margin-right: 16px;
}
.b-ripple {
top: 0;
right: 0;
bottom: 0;
left: 0;
position: absolute;
overflow: hidden;
}
.b-ripple:after {
top: 0;
right: 0;
bottom: 0;
left: 0;
content: "";
position: absolute;
pointer-events: none;
background-image: radial-gradient(circle, #000 10%, transparent 10%);
background-repeat: no-repeat;
background-position: 50%;
opacity: 0;
transition: transform 0.6s, opacity 0.6s;
transform: scale(10);
}
.b-ripple:active:after {
transform: scale(0);
opacity: 0.2;
transition: transform 0s, opacity 0s;
}
.b-ripple--primary:after {
background-image: radial-gradient(circle, #FF550B 10%, transparent 10%);
}
.b-ripple--secondary:after {
background-image: radial-gradient(circle, #303030 10%, transparent 10%);
}
.b-ripple--success:after {
background-image: radial-gradient(circle, #015668 10%, transparent 10%);
}
.b-ripple--info:after {
background-image: radial-gradient(circle, #0F81C7 10%, transparent 10%);
}
.b-ripple--warning:after {
background-image: radial-gradient(circle, #0DE2EA 10%, transparent 10%);
}
.b-ripple--danger:after {
background-image: radial-gradient(circle, #FF304F 10%, transparent 10%);
}
.b-ripple--light:after {
background-image: radial-gradient(circle, #e8e8e8 10%, transparent 10%);
}
.b-ripple--dark:after {
background-image: radial-gradient(circle, #000000 10%, transparent 10%);
}
html {
box-sizing: border-box;
height: 100%;
......@@ -7054,6 +7107,7 @@ a:focus {
width: inherit;
height: inherit;
border-radius: 3px;
border: 1px solid #6C757D;
}
.range-slider__knob {
user-select: none;
......@@ -7316,22 +7370,59 @@ input[type=range]:-moz-focusring {
width: 100%;
height: calc(100vh - 56px );
}
.graph-layout__frame {
top: 0;
right: 0;
bottom: 0;
left: 0;
position: absolute;
display: flex;
z-index: 2;
width: 100%;
height: calc(100vh - 56px);
justify-content: flex-end;
pointer-events: none;
}
.right-handed .graph-layout__frame {
flex-direction: row;
}
.left-handed .graph-layout__frame {
flex-direction: row-reverse;
}
.graph-layout__sidebar {
position: fixed;
width: 480px;
height: calc(100vh - 56px);
z-index: 2;
height: inherit;
flex-grow: 0;
pointer-events: all;
}
.right-handed .graph-layout__sidebar {
right: 0;
.graph-layout__sidebar__inner {
position: fixed;
height: inherit;
width: inherit;
}
.right-handed .graph-layout__sidebar__inner {
border-left: 1px solid #dee2e6;
}
.left-handed .graph-layout__sidebar {
left: 0;
.left-handed .graph-layout__sidebar__inner {
border-right: 1px solid #dee2e6;
}
.graph-layout__focus {
flex-grow: 1;
pointer-events: all;
position: relative;
}
.graph-layout__focus__inner {
top: 0;
right: 0;
bottom: 0;
left: 0;
position: absolute;
background-color: #000000;
}
.graph-layout__toolbar {
position: absolute;
z-index: 1;
......@@ -7487,6 +7578,35 @@ input[type=range]:-moz-focusring {
margin-top: 16px;
}
.graph-doc-list__item {
cursor: pointer;
display: flex;
align-items: flex-start;
transition: all 0.2s ease-in-out;
}
.graph-doc-list__item:focus {
outline: 0;
}
.graph-doc-list__item:hover {
background-color: #121212;
}
.graph-doc-list__item__main {
flex-grow: 1;
padding-right: 1.25rem;
}
.graph-doc-list__item__title, .graph-doc-list__item__source, .graph-doc-list__item__date {
line-height: 1.3;
margin-bottom: 4px;
}
.graph-doc-list__item__source {
font-size: 15px;
color: #DEE2E6;
}
.graph-doc-list__item__date {
font-size: 14px;
color: #CED4DA;
}
.graph-toolbar {
display: flex;
padding: 8px;
......
......@@ -6107,6 +6107,59 @@ h3 {
margin-right: 16px;
}
.b-ripple {
top: 0;
right: 0;
bottom: 0;
left: 0;
position: absolute;
overflow: hidden;
}
.b-ripple:after {
top: 0;
right: 0;
bottom: 0;
left: 0;
content: "";
position: absolute;
pointer-events: none;
background-image: radial-gradient(circle, #000 10%, transparent 10%);
background-repeat: no-repeat;
background-position: 50%;
opacity: 0;
transition: transform 0.6s, opacity 0.6s;
transform: scale(10);
}
.b-ripple:active:after {
transform: scale(0);
opacity: 0.2;
transition: transform 0s, opacity 0s;
}
.b-ripple--primary:after {
background-image: radial-gradient(circle, #005a9a 10%, transparent 10%);
}
.b-ripple--secondary:after {
background-image: radial-gradient(circle, #007bff 10%, transparent 10%);
}
.b-ripple--success:after {
background-image: radial-gradient(circle, #28a745 10%, transparent 10%);
}
.b-ripple--info:after {
background-image: radial-gradient(circle, #17a2b8 10%, transparent 10%);
}
.b-ripple--warning:after {
background-image: radial-gradient(circle, #ffc107 10%, transparent 10%);
}
.b-ripple--danger:after {
background-image: radial-gradient(circle, #dc3545 10%, transparent 10%);
}
.b-ripple--light:after {
background-image: radial-gradient(circle, #f8f9fa 10%, transparent 10%);
}
.b-ripple--dark:after {
background-image: radial-gradient(circle, #343a40 10%, transparent 10%);
}
html {
box-sizing: border-box;
height: 100%;
......@@ -7007,6 +7060,7 @@ a:focus {
width: inherit;
height: inherit;
border-radius: 3px;
border: 1px solid #CED4DA;
}
.range-slider__knob {
user-select: none;
......@@ -7269,22 +7323,59 @@ input[type=range]:-moz-focusring {
width: 100%;
height: calc(100vh - 56px );
}
.graph-layout__frame {
top: 0;
right: 0;
bottom: 0;
left: 0;
position: absolute;
display: flex;
z-index: 2;
width: 100%;
height: calc(100vh - 56px);
justify-content: flex-end;
pointer-events: none;
}
.right-handed .graph-layout__frame {
flex-direction: row;
}
.left-handed .graph-layout__frame {
flex-direction: row-reverse;
}
.graph-layout__sidebar {
position: fixed;
width: 480px;
height: calc(100vh - 56px);
z-index: 2;
height: inherit;
flex-grow: 0;
pointer-events: all;
}
.right-handed .graph-layout__sidebar {
right: 0;
.graph-layout__sidebar__inner {
position: fixed;
height: inherit;
width: inherit;
}
.right-handed .graph-layout__sidebar__inner {
border-left: 1px solid #dee2e6;
}
.left-handed .graph-layout__sidebar {
left: 0;
.left-handed .graph-layout__sidebar__inner {
border-right: 1px solid #dee2e6;
}
.graph-layout__focus {
flex-grow: 1;
pointer-events: all;
position: relative;
}
.graph-layout__focus__inner {
top: 0;
right: 0;
bottom: 0;
left: 0;
position: absolute;
background-color: #fff;
}
.graph-layout__toolbar {
position: absolute;
z-index: 1;
......@@ -7440,6 +7531,35 @@ input[type=range]:-moz-focusring {
margin-top: 16px;
}
.graph-doc-list__item {
cursor: pointer;
display: flex;
align-items: flex-start;
transition: all 0.2s ease-in-out;
}
.graph-doc-list__item:focus {
outline: 0;
}
.graph-doc-list__item:hover {
background-color: #FCFCFC;
}
.graph-doc-list__item__main {
flex-grow: 1;
padding-right: 1.25rem;
}
.graph-doc-list__item__title, .graph-doc-list__item__source, .graph-doc-list__item__date {
line-height: 1.3;
margin-bottom: 4px;
}
.graph-doc-list__item__source {
font-size: 15px;
color: #495057;
}
.graph-doc-list__item__date {
font-size: 14px;
color: #6C757D;
}
.graph-toolbar {
display: flex;
padding: 8px;
......
......@@ -5863,6 +5863,59 @@ h3 {
margin-right: 16px;
}
.b-ripple {
top: 0;
right: 0;
bottom: 0;
left: 0;
position: absolute;
overflow: hidden;
}
.b-ripple:after {
top: 0;
right: 0;
bottom: 0;
left: 0;
content: "";
position: absolute;
pointer-events: none;
background-image: radial-gradient(circle, #000 10%, transparent 10%);
background-repeat: no-repeat;
background-position: 50%;
opacity: 0;
transition: transform 0.6s, opacity 0.6s;
transform: scale(10);
}
.b-ripple:active:after {
transform: scale(0);
opacity: 0.2;
transition: transform 0s, opacity 0s;
}
.b-ripple--primary:after {
background-image: radial-gradient(circle, #2f3c48 10%, transparent 10%);
}
.b-ripple--secondary:after {
background-image: radial-gradient(circle, #6f7f8c 10%, transparent 10%);
}
.b-ripple--success:after {
background-image: radial-gradient(circle, #3e4d59 10%, transparent 10%);
}
.b-ripple--info:after {
background-image: radial-gradient(circle, #5c8f94 10%, transparent 10%);
}
.b-ripple--warning:after {
background-image: radial-gradient(circle, #6e9fa5 10%, transparent 10%);
}
.b-ripple--danger:after {
background-image: radial-gradient(circle, #cc330d 10%, transparent 10%);
}
.b-ripple--light:after {
background-image: radial-gradient(circle, #eceeec 10%, transparent 10%);
}
.b-ripple--dark:after {
background-image: radial-gradient(circle, #1e2b37 10%, transparent 10%);
}
html {
box-sizing: border-box;
height: 100%;
......@@ -6763,6 +6816,7 @@ a:focus {
width: inherit;
height: inherit;
border-radius: 3px;
border: 1px solid #CED4DA;
}
.range-slider__knob {
user-select: none;
......@@ -7025,22 +7079,59 @@ input[type=range]:-moz-focusring {
width: 100%;
height: calc(100vh - 56px );
}
.graph-layout__frame {
top: 0;
right: 0;
bottom: 0;
left: 0;
position: absolute;
display: flex;
z-index: 2;
width: 100%;
height: calc(100vh - 56px);
justify-content: flex-end;
pointer-events: none;
}
.right-handed .graph-layout__frame {
flex-direction: row;
}
.left-handed .graph-layout__frame {
flex-direction: row-reverse;
}
.graph-layout__sidebar {
position: fixed;
width: 480px;
height: calc(100vh - 56px);
z-index: 2;
height: inherit;
flex-grow: 0;
pointer-events: all;
}
.right-handed .graph-layout__sidebar {
right: 0;
.graph-layout__sidebar__inner {
position: fixed;
height: inherit;
width: inherit;
}
.right-handed .graph-layout__sidebar__inner {
border-left: 1px solid #dee2e6;
}
.left-handed .graph-layout__sidebar {
left: 0;
.left-handed .graph-layout__sidebar__inner {
border-right: 1px solid #dee2e6;
}
.graph-layout__focus {
flex-grow: 1;
pointer-events: all;
position: relative;
}
.graph-layout__focus__inner {
top: 0;
right: 0;
bottom: 0;
left: 0;
position: absolute;
background-color: #fff;
}
.graph-layout__toolbar {
position: absolute;
z-index: 1;
......@@ -7196,6 +7287,35 @@ input[type=range]:-moz-focusring {
margin-top: 16px;
}
.graph-doc-list__item {
cursor: pointer;
display: flex;
align-items: flex-start;
transition: all 0.2s ease-in-out;
}
.graph-doc-list__item:focus {
outline: 0;
}
.graph-doc-list__item:hover {
background-color: #FCFCFC;
}
.graph-doc-list__item__main {
flex-grow: 1;
padding-right: 1.25rem;
}
.graph-doc-list__item__title, .graph-doc-list__item__source, .graph-doc-list__item__date {
line-height: 1.3;
margin-bottom: 4px;
}
.graph-doc-list__item__source {
font-size: 15px;
color: #495057;
}
.graph-doc-list__item__date {
font-size: 14px;
color: #6C757D;
}
.graph-toolbar {
display: flex;
padding: 8px;
......
......@@ -6111,6 +6111,59 @@ h3 {
margin-right: 16px;
}
.b-ripple {
top: 0;
right: 0;
bottom: 0;
left: 0;
position: absolute;
overflow: hidden;
}
.b-ripple:after {
top: 0;
right: 0;
bottom: 0;
left: 0;
content: "";
position: absolute;
pointer-events: none;
background-image: radial-gradient(circle, #000 10%, transparent 10%);
background-repeat: no-repeat;
background-position: 50%;
opacity: 0;
transition: transform 0.6s, opacity 0.6s;
transform: scale(10);
}
.b-ripple:active:after {
transform: scale(0);
opacity: 0.2;
transition: transform 0s, opacity 0s;
}
.b-ripple--primary:after {
background-image: radial-gradient(circle, #083358 10%, transparent 10%);
}
.b-ripple--secondary:after {
background-image: radial-gradient(circle, #F67280 10%, transparent 10%);
}
.b-ripple--success:after {
background-image: radial-gradient(circle, #0074E4 10%, transparent 10%);
}
.b-ripple--info:after {
background-image: radial-gradient(circle, #74DBEF 10%, transparent 10%);
}
.b-ripple--warning:after {
background-image: radial-gradient(circle, #FC3C3C 10%, transparent 10%);
}
.b-ripple--danger:after {
background-image: radial-gradient(circle, #FF4057 10%, transparent 10%);
}
.b-ripple--light:after {
background-image: radial-gradient(circle, #F2F2F0 10%, transparent 10%);
}
.b-ripple--dark:after {
background-image: radial-gradient(circle, #072247 10%, transparent 10%);
}
html {
box-sizing: border-box;
height: 100%;
......@@ -7011,6 +7064,7 @@ a:focus {
width: inherit;
height: inherit;
border-radius: 3px;
border: 1px solid #CED4DA;
}
.range-slider__knob {
user-select: none;
......@@ -7273,22 +7327,59 @@ input[type=range]:-moz-focusring {
width: 100%;
height: calc(100vh - 56px );
}
.graph-layout__frame {
top: 0;
right: 0;
bottom: 0;
left: 0;
position: absolute;
display: flex;
z-index: 2;
width: 100%;
height: calc(100vh - 56px);
justify-content: flex-end;
pointer-events: none;
}
.right-handed .graph-layout__frame {
flex-direction: row;
}
.left-handed .graph-layout__frame {
flex-direction: row-reverse;
}
.graph-layout__sidebar {
position: fixed;
width: 480px;
height: calc(100vh - 56px);
z-index: 2;
height: inherit;
flex-grow: 0;
pointer-events: all;
}
.right-handed .graph-layout__sidebar {
right: 0;
.graph-layout__sidebar__inner {
position: fixed;
height: inherit;
width: inherit;
}
.right-handed .graph-layout__sidebar__inner {
border-left: 1px solid #dee2e6;
}
.left-handed .graph-layout__sidebar {
left: 0;
.left-handed .graph-layout__sidebar__inner {
border-right: 1px solid #dee2e6;
}
.graph-layout__focus {
flex-grow: 1;
pointer-events: all;
position: relative;
}
.graph-layout__focus__inner {
top: 0;
right: 0;
bottom: 0;
left: 0;
position: absolute;
background-color: #fff;
}
.graph-layout__toolbar {
position: absolute;
z-index: 1;
......@@ -7444,6 +7535,35 @@ input[type=range]:-moz-focusring {
margin-top: 16px;
}
.graph-doc-list__item {
cursor: pointer;
display: flex;
align-items: flex-start;
transition: all 0.2s ease-in-out;
}
.graph-doc-list__item:focus {
outline: 0;
}
.graph-doc-list__item:hover {
background-color: #FCFCFC;
}
.graph-doc-list__item__main {
flex-grow: 1;
padding-right: 1.25rem;
}
.graph-doc-list__item__title, .graph-doc-list__item__source, .graph-doc-list__item__date {
line-height: 1.3;
margin-bottom: 4px;
}
.graph-doc-list__item__source {
font-size: 15px;
color: #495057;
}
.graph-doc-list__item__date {
font-size: 14px;
color: #6C757D;
}
.graph-toolbar {
display: flex;
padding: 8px;
......
......@@ -6112,6 +6112,59 @@ h3 {
margin-right: 16px;
}
.b-ripple {
top: 0;
right: 0;
bottom: 0;
left: 0;
position: absolute;
overflow: hidden;
}
.b-ripple:after {
top: 0;
right: 0;
bottom: 0;
left: 0;
content: "";
position: absolute;
pointer-events: none;
background-image: radial-gradient(circle, #000 10%, transparent 10%);
background-repeat: no-repeat;
background-position: 50%;
opacity: 0;
transition: transform 0.6s, opacity 0.6s;
transform: scale(10);
}
.b-ripple:active:after {
transform: scale(0);
opacity: 0.2;
transition: transform 0s, opacity 0s;
}
.b-ripple--primary:after {
background-image: radial-gradient(circle, #222222 10%, transparent 10%);
}
.b-ripple--secondary:after {
background-image: radial-gradient(circle, #666666 10%, transparent 10%);
}
.b-ripple--success:after {
background-image: radial-gradient(circle, #333333 10%, transparent 10%);
}
.b-ripple--info:after {
background-image: radial-gradient(circle, #515151 10%, transparent 10%);
}
.b-ripple--warning:after {
background-image: radial-gradient(circle, #5f5f5f 10%, transparent 10%);
}
.b-ripple--danger:after {
background-image: radial-gradient(circle, #434343 10%, transparent 10%);
}
.b-ripple--light:after {
background-image: radial-gradient(circle, #eceeec 10%, transparent 10%);
}
.b-ripple--dark:after {
background-image: radial-gradient(circle, #111111 10%, transparent 10%);
}
html {
box-sizing: border-box;
height: 100%;
......@@ -7012,6 +7065,7 @@ a:focus {
width: inherit;
height: inherit;
border-radius: 3px;
border: 1px solid #CED4DA;
}
.range-slider__knob {
user-select: none;
......@@ -7274,22 +7328,59 @@ input[type=range]:-moz-focusring {
width: 100%;
height: calc(100vh - 56px );
}
.graph-layout__frame {
top: 0;
right: 0;
bottom: 0;
left: 0;
position: absolute;
display: flex;
z-index: 2;
width: 100%;
height: calc(100vh - 56px);
justify-content: flex-end;
pointer-events: none;
}
.right-handed .graph-layout__frame {
flex-direction: row;
}
.left-handed .graph-layout__frame {
flex-direction: row-reverse;
}
.graph-layout__sidebar {
position: fixed;
width: 480px;
height: calc(100vh - 56px);
z-index: 2;
height: inherit;
flex-grow: 0;
pointer-events: all;
}
.right-handed .graph-layout__sidebar {
right: 0;
.graph-layout__sidebar__inner {
position: fixed;
height: inherit;
width: inherit;
}
.right-handed .graph-layout__sidebar__inner {
border-left: 1px solid #dee2e6;
}
.left-handed .graph-layout__sidebar {
left: 0;
.left-handed .graph-layout__sidebar__inner {
border-right: 1px solid #dee2e6;
}
.graph-layout__focus {
flex-grow: 1;
pointer-events: all;
position: relative;
}
.graph-layout__focus__inner {
top: 0;
right: 0;
bottom: 0;
left: 0;
position: absolute;
background-color: #fff;
}
.graph-layout__toolbar {
position: absolute;
z-index: 1;
......@@ -7445,6 +7536,35 @@ input[type=range]:-moz-focusring {
margin-top: 16px;
}
.graph-doc-list__item {
cursor: pointer;
display: flex;
align-items: flex-start;
transition: all 0.2s ease-in-out;
}
.graph-doc-list__item:focus {
outline: 0;
}
.graph-doc-list__item:hover {
background-color: #FCFCFC;
}
.graph-doc-list__item__main {
flex-grow: 1;
padding-right: 1.25rem;
}
.graph-doc-list__item__title, .graph-doc-list__item__source, .graph-doc-list__item__date {
line-height: 1.3;
margin-bottom: 4px;
}
.graph-doc-list__item__source {
font-size: 15px;
color: #495057;
}
.graph-doc-list__item__date {
font-size: 14px;
color: #6C757D;
}
.graph-toolbar {
display: flex;
padding: 8px;
......
......@@ -6,7 +6,6 @@ import Gargantext.Prelude
import Data.Maybe (Maybe(..))
import Data.Set as Set
import Gargantext.AsyncTasks as GAT
import Gargantext.Components.GraphExplorer.Sidebar.Types as GEST
import Gargantext.Components.Lang as Lang
import Gargantext.Components.Nodes.Lists.Types as ListsT
import Gargantext.Components.Nodes.Texts.Types as TextsT
......@@ -36,7 +35,6 @@ type App =
, showCorpus :: Boolean
, showLogin :: Boolean
, showTree :: Boolean
, sidePanelGraph :: Maybe (Record GEST.SidePanel)
, sidePanelLists :: Maybe (Record ListsT.SidePanel)
, sidePanelTexts :: Maybe (Record TextsT.SidePanel)
, sidePanelState :: SidePanelState
......@@ -63,7 +61,6 @@ emptyApp =
, showCorpus : false
, showLogin : false
, showTree : true
, sidePanelGraph : GEST.initialSidePanel
, sidePanelLists : ListsT.initialSidePanel
, sidePanelTexts : TextsT.initialSidePanel
, sidePanelState : InitialClosed
......@@ -89,7 +86,6 @@ type Boxes =
, showCorpus :: T.Box Boolean
, showLogin :: T.Box Boolean
, showTree :: T.Box Boolean
, sidePanelGraph :: T.Box (Maybe (Record GEST.SidePanel))
, sidePanelLists :: T.Box (Maybe (Record ListsT.SidePanel))
, sidePanelTexts :: T.Box (Maybe (Record TextsT.SidePanel))
, sidePanelState :: T.Box SidePanelState
......
module Gargantext.Components.Bootstrap.Ripple
( ripple
) where
import Gargantext.Prelude
import Data.Foldable (intercalate)
import Gargantext.Components.Bootstrap.Types (ComponentStatus(..), Variant(..))
import Gargantext.Utils.Reactix as R2
import Reactix as R
import Reactix.DOM.HTML as H
type Props = ( | Options )
type Options =
( status :: ComponentStatus
, className :: String
, variant :: Variant
)
options :: Record Options
options =
{ variant : Light
, status : Enabled
, className : ""
}
-- | Component for a Ripple Effect on DOMElement click (without JavaScript)
-- |
-- | ```
-- | B.ripple
-- | {}
-- | [
-- | myContent {} []
-- | ]
-- | ```
ripple :: forall r. R2.OptComponent Options Props r
ripple = R2.optComponent component options
componentName :: String
componentName = "b-ripple"
component :: R.Component Props
component = R.hooksComponent componentName cpt where
cpt props@{ variant
, status
} children = do
-- Computed
let
className = intercalate " "
-- provided custom className
[ props.className
-- BEM classNames
, componentName
, componentName <> "--" <> show status
, componentName <> "--" <> show variant
]
-- Render
pure $
R.fragment $
[
H.div
{ className }
[]
]
<> children
......@@ -13,6 +13,7 @@ import Gargantext.Components.Bootstrap.FormTextarea(formTextarea) as Exports
import Gargantext.Components.Bootstrap.Icon(icon) as Exports
import Gargantext.Components.Bootstrap.IconButton(iconButton) as Exports
import Gargantext.Components.Bootstrap.ProgressBar(progressBar) as Exports
import Gargantext.Components.Bootstrap.Ripple(ripple) as Exports
import Gargantext.Components.Bootstrap.Spinner(spinner) as Exports
import Gargantext.Components.Bootstrap.Tabs(tabs) as Exports
import Gargantext.Components.Bootstrap.Tooltip(tooltip, TooltipBindingProps, tooltipBind, tooltipBind', tooltipContainer) as Exports
......
......@@ -2,7 +2,7 @@ module Gargantext.Components.Bootstrap.BaseModal (baseModal) where
import Gargantext.Prelude
import DOM.Simple (Window)
import DOM.Simple (Window, window)
import Data.Foldable (intercalate)
import Effect (Effect)
import Effect.Uncurried (EffectFn2, runEffectFn2)
......@@ -56,8 +56,8 @@ component = R.hooksComponent componentName cpt where
isVisible <- R2.useLive' isVisibleBox
-- Hooks
-- R.useEffect1' isVisible $
-- (isVisible ? addClassName $ removeClassName) window "modal-open"
R.useEffect1' isVisible $
(isVisible ? addClassName $ removeClassName) window "modal-open"
-- Computed
let
......@@ -81,6 +81,7 @@ component = R.hooksComponent componentName cpt where
, className
, role: "dialog"
, data: { show: true }
, key: id
}
[
R2.if' (hasBackground) $
......
......@@ -54,6 +54,7 @@ import Gargantext.Utils.Toestand as GUT
import Gargantext.Utils.Toestand as T2
import Reactix as R
import Reactix.DOM.HTML as H
import Record.Extra as RX
import Simple.JSON as JSON
import Toestand as T
......@@ -94,8 +95,7 @@ type LayoutProps =
)
type PageLayoutProps =
( key :: String -- NOTE Necessary to clear the component when cache state changes
, params :: TT.Params
( params :: TT.Params
, query :: Query
| CommonProps
)
......@@ -377,9 +377,10 @@ filterDocsByYear year docs = A.filter filterFunc docs
filterFunc :: Response -> Boolean
filterFunc (Response { hyperdata: Hyperdata { pub_year } }) = eq year $ show pub_year
pageLayout :: R2.Component PageLayoutProps
-- NOTE "key": Necessary to clear the component when cache state changes
pageLayout :: R2.Component ( key :: String | PageLayoutProps )
pageLayout = R.createElement pageLayoutCpt
pageLayoutCpt :: R.Component PageLayoutProps
pageLayoutCpt :: R.Component ( key :: String | PageLayoutProps )
pageLayoutCpt = here.component "pageLayout" cpt where
cpt props@{ boxes
, cacheState
......@@ -395,6 +396,8 @@ pageLayoutCpt = here.component "pageLayout" cpt where
cacheState' <- T.useLive T.unequal cacheState
yearFilter' <- T.useLive T.unequal yearFilter
let props' = (RX.pick props :: Record PageLayoutProps)
let path = { listId, mCorpusId, nodeId, params, query, tabType, yearFilter: yearFilter' }
handleResponse :: HashedResponse (TableResult Response) -> Tuple Int (Array DocumentsView)
handleResponse (HashedResponse { value: res }) = ret
......@@ -419,7 +422,7 @@ pageLayoutCpt = here.component "pageLayout" cpt where
NT.CacheOn -> do
let paint (Tuple count docs) = page { boxes
, documents: docs
, layout: props { totalRecords = count }
, layout: props' { totalRecords = count }
, params } []
mkRequest :: PageParams -> GUC.Request
mkRequest p = GUC.makeGetRequest session $ tableRoute p
......@@ -444,7 +447,7 @@ pageLayoutCpt = here.component "pageLayout" cpt where
-- here.log2 "table res" eRes
pure $ handleResponse <$> eRes
let render (Tuple count documents) = pagePaintRaw { documents
, layout: props { params = paramsS'
, layout: props' { params = paramsS'
, totalRecords = count }
, localCategories
, params: paramsS } []
......
......@@ -35,7 +35,7 @@ errorsViewCpt = here.component "errorsView" cpt
, variant: "danger" } [ H.text error ]
where
onClose = do
here.log2 "click!" error
here.error2 "click!" error
T.modify_ (\es -> case deleteAt i es of
Nothing -> es
Just es' -> es'
......@@ -46,7 +46,7 @@ errorsViewCpt = here.component "errorsView" cpt
, variant: "danger" } [ H.text $ show error ]
where
onClose = do
here.log2 "click!" error
here.error2 "click!" error
T.modify_ (\es -> case deleteAt i es of
Nothing -> es
Just es' -> es'
......@@ -57,7 +57,7 @@ errorsViewCpt = here.component "errorsView" cpt
, variant: "danger" } [ H.text $ show error ]
where
onClose = do
here.log2 "click!" error
here.error2 "click!" error
T.modify_ (\es -> case deleteAt i es of
Nothing -> es
Just es' -> es'
......
......@@ -311,9 +311,9 @@ pageLayoutCpt = here.component "pageLayout" cpt
, path: path'
, render: \rowsLoaded -> page { container, deletions, frontends, path, rowsLoaded, session, totalRecords } [] }
errorHandler err = do
here.log2 "[pageLayout] RESTError" err
here.warn2 "[pageLayout] RESTError" err
case err of
ReadJSONError err' -> here.log2 "[pageLayout] ReadJSONError" $ show err'
ReadJSONError err' -> here.warn2 "[pageLayout] ReadJSONError" $ show err'
_ -> pure unit
page :: R2.Component PageProps
......
......@@ -249,7 +249,13 @@ nodeSpanCpt = here.component "nodeSpan" cpt
R.createPortal
[
fileTypeView
{ dispatch, droppedFile, id, isDragOver, nodeType } []
{ dispatch
, droppedFile
, id
, isDragOver
, nodeType
, key: "fileType-" <> show id
}
]
host
,
......
......@@ -417,10 +417,11 @@ type FileTypeProps =
, id :: ID
, isDragOver :: T.Box Boolean
, nodeType :: GT.NodeType
, key :: String
)
fileTypeView :: R2.Component FileTypeProps
fileTypeView = R.createElement fileTypeViewCpt
fileTypeView :: R2.Leaf FileTypeProps
fileTypeView = R2.leaf fileTypeViewCpt
fileTypeViewCpt :: R.Component FileTypeProps
fileTypeViewCpt = here.component "fileTypeView" cpt
where
......@@ -431,15 +432,20 @@ fileTypeViewCpt = here.component "fileTypeView" cpt
} _ = do
droppedFile' <- T.useLive T.unequal droppedFile
case droppedFile' of
Nothing -> pure $ mempty
Just df ->
pure $ H.div tooltipProps [ H.div { className: "card"}
[ panelHeading
, panelBody df
, panelFooter df
]
]
pure $
R2.fromMaybe_ droppedFile' \df ->
H.div
tooltipProps
[
H.div { className: "card"}
[ panelHeading
, panelBody df
, panelFooter df
]
]
where
tooltipProps = { className: ""
, id : "file-type-tooltip"
......
This diff is collapsed.
......@@ -2,14 +2,17 @@ module Gargantext.Components.GraphExplorer.API where
import Gargantext.Prelude
import Data.Maybe (Maybe)
import Data.Maybe (Maybe(..))
import Gargantext.Components.GraphExplorer.Types as GET
import Gargantext.Components.NgramsTable.Core as NTC
import Gargantext.Config.REST (AffRESTError)
import Gargantext.Hooks.Sigmax.Types as SigmaxT
import Gargantext.Routes (SessionRoute(..))
import Gargantext.Routes as GR
import Gargantext.Sessions (Session, get, post)
import Gargantext.Types as GT
import Gargantext.Types as Types
import Gargantext.Utils.Toestand as T2
type GraphAsyncUpdateParams =
( graphId :: Int
......@@ -84,3 +87,11 @@ type CloneGraphParams =
cloneGraph :: Record CloneGraphParams -> AffRESTError Int
cloneGraph { hyperdataGraph, id, session } = post session (GR.GraphAPI id $ "clone") hyperdataGraph
-----------------------------------------------
getNodes :: Session -> T2.Reload -> GET.GraphId -> AffRESTError GET.HyperdataGraph
getNodes session graphVersion graphId =
get session $ NodeAPI Types.Graph
(Just graphId)
("?version=" <> (show graphVersion))
This diff is collapsed.
module Gargantext.Components.GraphExplorer.ControlsToggleButton
( Props, controlsToggleButton, controlsToggleButtonCpt
) where
import Reactix as R
import Reactix.DOM.HTML as H
import Toestand as T
import Gargantext.Prelude
import Gargantext.Utils.Reactix as R2
here :: R2.Here
here = R2.here "Gargantext.Components.GraphExplorer.ControlsToggleButton"
type Props = ( state :: T.Box Boolean )
controlsToggleButton :: R2.Leaf Props
controlsToggleButton = R2.leafComponent controlsToggleButtonCpt
controlsToggleButtonCpt :: R.Component Props
controlsToggleButtonCpt = here.component "controlsToggleButton" cpt
where
cpt { state } _ = do
open' <- T.useLive T.unequal state
pure $
H.button
{ className: "btn btn-primary", on: {click: \_ -> T.modify_ not state } }
[ H.text (text open') ]
text true = "Hide Controls"
text false = "Show Controls"
module Gargantext.Components.GraphExplorer.Frame.DocFocus
( docFocus
) where
import Gargantext.Prelude
import Data.Maybe (Maybe(..))
import Gargantext.Components.GraphExplorer.Types (GraphSideDoc(..))
import Gargantext.Components.Nodes.Corpus.Document (documentMainLayout)
import Gargantext.Sessions (Session)
import Gargantext.Utils.Reactix as R2
import Reactix as R
import Reactix.DOM.HTML as H
here :: R2.Here
here = R2.here "Gargantext.Components.GraphExplorer.Frame.DocFocus"
type Props =
( graphSideDoc :: GraphSideDoc
, session :: Session
)
docFocus :: R2.Leaf Props
docFocus = R2.leaf docFocusCpt
docFocusCpt :: R.Component Props
docFocusCpt = here.component "main" cpt where
cpt { graphSideDoc: GraphSideDoc { docId, listId, corpusId }
, session
} _ = do
-- | Render
-- |
pure $
H.div
{ className: "graph-layout__focus" }
[
H.div
{ className: "graph-layout__focus__inner" }
[
documentMainLayout
{ listId
, mCorpusId: Just corpusId
, nodeId: docId
, session
}
[]
]
]
module Gargantext.Components.GraphExplorer.Resources
-- ( graph, graphCpt
-- , sigmaSettings, SigmaSettings, SigmaOptionalSettings
-- , forceAtlas2Settings, ForceAtlas2Settings, ForceAtlas2OptionalSettings
-- )
( drawGraph
, sigmaSettings, SigmaSettings--, SigmaOptionalSettings
, forceAtlas2Settings, ForceAtlas2Settings--, ForceAtlas2OptionalSettings
)
where
import Gargantext.Prelude
......@@ -10,91 +10,83 @@ import Gargantext.Prelude
import DOM.Simple (window)
import DOM.Simple.Types (Element)
import Data.Either (Either(..))
import Data.Generic.Rep (class Generic)
import Data.Maybe (Maybe(..))
import Data.Nullable (Nullable)
import Gargantext.Components.App.Data (Boxes)
import Gargantext.Components.GraphExplorer.Store as GraphStore
import Gargantext.Components.GraphExplorer.Types as GET
import Gargantext.Components.Themes (darksterTheme)
import Gargantext.Components.Themes as Themes
import Gargantext.Hooks.Sigmax as Sigmax
import Gargantext.Hooks.Sigmax.Sigma as Sigma
import Gargantext.Hooks.Sigmax.Types as SigmaxTypes
import Gargantext.Utils (getter)
import Gargantext.Utils.Reactix as R2
import Gargantext.Utils.Stores as Stores
import Reactix as R
import Reactix.DOM.HTML as RH
import Record (merge)
import Record as Record
import Toestand as T
here :: R2.Here
here = R2.here "Gargantext.Components.Graph"
data Stage = Init | Ready | Cleanup
derive instance Generic Stage _
derive instance Eq Stage
type Props sigma forceatlas2 =
( boxes :: Boxes
, elRef :: R.Ref (Nullable Element)
, forceAtlas2Settings :: forceatlas2
, graph :: SigmaxTypes.SGraph
, mCamera :: Maybe GET.Camera
, multiSelectEnabledRef :: R.Ref Boolean
, selectedNodeIds :: T.Box SigmaxTypes.NodeIds
, showEdges :: T.Box SigmaxTypes.ShowEdgesState
, sigmaRef :: R.Ref Sigmax.Sigma
, sigmaSettings :: sigma
, stage :: T.Box Stage
, startForceAtlas :: Boolean
, transformedGraph :: SigmaxTypes.SGraph
)
graph :: forall s fa2. R2.Component (Props s fa2)
graph = R.createElement graphCpt
graphCpt :: forall s fa2. R.Memo (Props s fa2)
graphCpt = R.memo' $ here.component "graph" cpt where
cpt props@{ elRef
, showEdges
, sigmaRef
, stage } _ = do
showEdges' <- T.useLive T.unequal showEdges
stage' <- T.useLive T.unequal stage
stageHooks (Record.merge { showEdges', stage' } props)
R.useEffectOnce $ do
pure $ do
here.log "[graphCpt (Cleanup)]"
Sigmax.dependOnSigma (R.readRef sigmaRef) "[graphCpt (Cleanup)] no sigma" $ \sigma -> do
Sigma.stopForceAtlas2 sigma
here.log2 "[graphCpt (Cleanup)] forceAtlas stopped for" sigma
Sigma.kill sigma
here.log "[graphCpt (Cleanup)] sigma killed"
-- NOTE: This div is not empty after sigma initializes.
-- When we change state, we make it empty though.
--pure $ RH.div { ref: elRef, style: {height: "95%"} } []
pure $ case R.readNullableRef elRef of
Nothing -> RH.div {} []
Just el -> R.createPortal [] el
stageHooks { elRef
, mCamera
, multiSelectEnabledRef
, selectedNodeIds
, forceAtlas2Settings: fa2
, graph: graph'
, sigmaRef
, stage
, stage': Init
, startForceAtlas
, boxes
} = do
R.useEffectOnce' $ do
drawGraph :: forall s fa2. R2.Leaf (Props s fa2)
drawGraph = R2.leaf drawGraphCpt
drawGraphCpt :: forall s fa2. R.Memo (Props s fa2)
drawGraphCpt = R.memo' $ here.component "graph" cpt where
-- | Component
-- |
cpt { elRef
, sigmaRef
, boxes
, forceAtlas2Settings: fa2
, transformedGraph
} _ = do
{ showEdges
, graphStage
, graph
, startForceAtlas
, selectedNodeIds
, multiSelectEnabled
, hyperdataGraph
} <- Stores.useStore GraphStore.context
showEdges' <- R2.useLive' showEdges
graphStage' <- R2.useLive' graphStage
graph' <- R2.useLive' graph
startForceAtlas' <- R2.useLive' startForceAtlas
hyperdataGraph' <- R2.useLive' hyperdataGraph
selectedNodeIds' <- R2.useLive' selectedNodeIds
-- | Hooks
-- |
-- Clean up
R.useEffectOnce $ do
pure $ do
here.log "[graphCpt (Cleanup)]"
Sigmax.dependOnSigma (R.readRef sigmaRef) "[graphCpt (Cleanup)] no sigma" $ \sigma -> do
Sigma.stopForceAtlas2 sigma
here.log2 "[graphCpt (Cleanup)] forceAtlas stopped for" sigma
Sigma.kill sigma
here.log "[graphCpt (Cleanup)] sigma killed"
-- Stage Init
R.useEffect1' graphStage' $ case graphStage' of
GET.Init -> do
let mCamera = getter _.mCamera hyperdataGraph'
let rSigma = R.readRef sigmaRef
case Sigmax.readSigma rSigma of
......@@ -102,7 +94,7 @@ graphCpt = R.memo' $ here.component "graph" cpt where
theme <- T.read boxes.theme
eSigma <- Sigma.sigma {settings: sigmaSettings theme}
case eSigma of
Left err -> here.log2 "[graphCpt] error creating sigma" err
Left err -> here.warn2 "[graphCpt] error creating sigma" err
Right sig -> do
Sigmax.writeSigma rSigma $ Just sig
......@@ -118,14 +110,14 @@ graphCpt = R.memo' $ here.component "graph" cpt where
Sigmax.dependOnSigma (R.readRef sigmaRef) "[graphCpt (Ready)] no sigma" $ \sigma -> do
-- bind the click event only initially, when ref was empty
Sigmax.bindSelectedNodesClick sigma selectedNodeIds multiSelectEnabledRef
Sigmax.bindSelectedNodesClick sigma selectedNodeIds multiSelectEnabled
_ <- Sigma.bindMouseSelectorPlugin sigma
pure unit
Sigmax.setEdges sig false
-- here.log2 "[graph] startForceAtlas" startForceAtlas
if startForceAtlas then
if startForceAtlas' then
Sigma.startForceAtlas2 sig fa2
else
Sigma.stopForceAtlas2 sig
......@@ -147,19 +139,19 @@ graphCpt = R.memo' $ here.component "graph" cpt where
Just _sig -> do
pure unit
T.write Ready stage
T.write_ GET.Ready graphStage
_ -> pure unit
stageHooks { showEdges'
, sigmaRef
, stage': Ready
, transformedGraph
} = do
let tEdgesMap = SigmaxTypes.edgesGraphMap transformedGraph
let tNodesMap = SigmaxTypes.nodesGraphMap transformedGraph
-- Stage ready
-- (?) Probably this can be optimized to re-mark selected nodes only when
-- they changed → done on #375
R.useEffect1' selectedNodeIds' case graphStage' of
GET.Ready -> do
let tEdgesMap = SigmaxTypes.edgesGraphMap transformedGraph
let tNodesMap = SigmaxTypes.nodesGraphMap transformedGraph
-- TODO Probably this can be optimized to re-mark selected nodes only when they changed
R.useEffect' $ do
Sigmax.dependOnSigma (R.readRef sigmaRef) "[graphCpt (Ready)] no sigma" $ \sigma -> do
Sigmax.performDiff sigma transformedGraph
Sigmax.updateEdges sigma tEdgesMap
......@@ -168,8 +160,18 @@ graphCpt = R.memo' $ here.component "graph" cpt where
here.log2 "[graphCpt] edgesState" edgesState
Sigmax.setEdges sigma edgesState
_ -> pure unit
-- | Render
-- |
pure $
R2.fromMaybe_ (R.readNullableRef elRef) (R.createPortal [])
stageHooks _ = pure unit
-- NOTE: This div is not empty after sigma initializes.
-- When we change state, we make it empty though.
--pure $ RH.div { ref: elRef, style: {height: "95%"} } []
type SigmaSettings =
......
module Gargantext.Components.GraphExplorer.Sidebar.DocList
( docList
) where
import Gargantext.Prelude
import Data.Foldable (intercalate)
import Data.Maybe (Maybe(..))
import Data.Sequence as Seq
import Data.Tuple.Nested ((/\))
import Effect (Effect)
import Gargantext.Components.Bootstrap as B
import Gargantext.Components.Bootstrap.Types (Variant(..))
import Gargantext.Components.FacetsTable (DocumentsView(..), PagePath, Rows(..), initialPagePath, loadPage, publicationDate)
import Gargantext.Components.GraphExplorer.Types (GraphSideCorpus(..), GraphSideDoc(..), DocId)
import Gargantext.Components.Search (SearchQuery)
import Gargantext.Config.REST (RESTError(..))
import Gargantext.Ends (Frontends)
import Gargantext.Hooks.Loader (useLoaderEffect)
import Gargantext.Hooks.UpdateEffect (useUpdateEffect1')
import Gargantext.Sessions (Session)
import Gargantext.Utils ((?))
import Gargantext.Utils.Reactix as R2
import Reactix as R
import Reactix.DOM.HTML as H
import Toestand as T
here :: R2.Here
here = R2.here "Gargantext.Components.GraphExplorer.Sidebar.DocList"
type TabsProps =
( frontends :: Frontends
, query :: SearchQuery
, session :: Session
, graphSideCorpus :: GraphSideCorpus
, showDoc :: T.Box (Maybe GraphSideDoc)
)
docList :: R2.Leaf TabsProps
docList = R2.leaf docListCpt
docListCpt :: R.Component TabsProps
docListCpt = here.component "main" cpt where
-- | Helpers
-- |
errorHandler err = do
here.warn2 "[pageLayout] RESTError" err
case err of
ReadJSONError err' ->
here.warn2 "[pageLayout] ReadJSONError" $ show err'
_ -> pure unit
-- | Component
-- |
cpt { frontends
, query
, session
, graphSideCorpus: GraphSideCorpus
{ corpusId: nodeId
, listId
}
, showDoc
} _ = do
-- | States
-- |
path' /\ path
<- R2.useBox' $ initialPagePath { nodeId, listId, query, session }
state' /\ state <-
R2.useBox' Nothing
rows' /\ rows <-
R2.useBox' Nothing
showDoc' <-
R2.useLive' showDoc
-- | Hooks
-- |
useLoaderEffect
{ errorHandler
, state
, loader: loadPage
, path: path'
}
-- | Effects
-- |
-- (on query change, reload fetched docs)
useUpdateEffect1' query $
flip T.write_ path $ initialPagePath { nodeId, listId, query, session }
-- (on fetch success, extract existing docs)
useUpdateEffect1' state' case state' of
Nothing -> T.write_ (Just Seq.empty) rows
Just r -> case r of
Docs { docs } -> T.write_ (Just docs) rows
_ -> T.write_ (Just Seq.empty) rows
-- | Computed
-- |
let
callback :: Maybe GraphSideDoc -> DocId -> Effect Unit
callback
Nothing
new
= setGraphSideDoc new # Just # flip T.write_ showDoc
callback
(Just (GraphSideDoc { docId }))
new
| docId == new = T.write_ Nothing showDoc
| otherwise = setGraphSideDoc new # Just # flip T.write_ showDoc
setGraphSideDoc :: DocId -> GraphSideDoc
setGraphSideDoc docId = GraphSideDoc
{ docId
, listId
, corpusId: nodeId
}
isSelected :: Maybe GraphSideDoc -> DocumentsView -> Boolean
isSelected
(Just (GraphSideDoc { docId }))
(DocumentsView { id })
= docId == id
isSelected
_
_
= false
-- | Render
-- |
pure $
R2.fromMaybe_ rows' \results ->
R.fragment
[
R2.if' (results == Seq.empty) $
B.caveat
{}
[
H.text "No docs found in your corpus for your selected terms"
]
,
R2.if' (not $ eq results Seq.empty) $
H.ul
{ className: intercalate " "
[ "graph-doc-list"
, "list-group"
]
} $
Seq.toUnfoldable $ flip Seq.map results \r ->
item
{ frontends
, path: path'
, session
, documentView: (r :: DocumentsView)
, callback: callback showDoc'
, isSelected: isSelected showDoc' (r :: DocumentsView)
}
]
---------------------------------------------------------
type ItemProps =
( documentView :: DocumentsView
, frontends :: Frontends
, session :: Session
, path :: PagePath
, callback :: DocId -> Effect Unit
, isSelected :: Boolean
)
item :: R2.Leaf ItemProps
item = R2.leaf itemCpt
itemCpt :: R.Component ItemProps
itemCpt = here.component "item" cpt where
cpt { documentView: dv@(DocumentsView { id, title, source })
, callback
, isSelected
-- , frontends
-- , path
-- , session
} _ = do
-- Computed
-- let
-- Creating a href link
-- documentUrl id' { listId, nodeId } =
-- url frontends $ Routes.CorpusDocument (sessionId session) nodeId listId id'
-- Render
pure $
H.div
{ className: intercalate " "
[ "graph-doc-list__item"
, "list-group-item"
]
, on: { click: \_ -> callback id }
}
[
B.ripple
{ variant: Dark }
[
H.div
{ className: "graph-doc-list__item__main" }
[
B.div'
{ className: "graph-doc-list__item__title" }
title
,
B.div'
{ className: "graph-doc-list__item__source" }
source
,
B.div'
{ className: "graph-doc-list__item__date" } $
publicationDate dv
]
,
H.div
{ className: "graph-doc-list__item__aside" }
[
B.icon
{ name: "eye-slash"
, className: intercalate " "
[ "text-info"
, isSelected ? "visible" $ "hidden"
]
}
]
]
]
module Gargantext.Components.GraphExplorer.Legend
module Gargantext.Components.GraphExplorer.Sidebar.Legend
( Props, legend
) where
......@@ -13,7 +13,7 @@ import Gargantext.Components.GraphExplorer.Types (Legend(..), intColor)
import Gargantext.Utils.Reactix as R2
here :: R2.Here
here = R2.here "Gargantext.Components.GraphExplorer.Legend"
here = R2.here "Gargantext.Components.GraphExplorer.Sidebar.Legend"
type Props = ( items :: Seq Legend )
......
module Gargantext.Components.GraphExplorer.Sidebar.Types where
import Gargantext.Prelude
import Data.Maybe (Maybe(..), maybe)
import Data.Set as Set
import Gargantext.Components.GraphExplorer.Types as GET
import Gargantext.Hooks.Sigmax.Types as SigmaxT
import Gargantext.Types as GT
import Reactix as R
import Toestand as T
type SidePanel =
(
mGraph :: Maybe SigmaxT.SGraph
, mMetaData :: Maybe GET.MetaData
, multiSelectEnabled :: Boolean
, removedNodeIds :: SigmaxT.NodeIds
, selectedNodeIds :: SigmaxT.NodeIds
, showControls :: Boolean
, sideTab :: GET.SideTab
, showSidebar :: GT.SidePanelState
)
initialSidePanel :: Maybe (Record SidePanel)
initialSidePanel = Nothing
focusedSidePanel :: T.Box (Maybe (Record SidePanel))
-> R.Hooks { mGraph :: T.Box (Maybe SigmaxT.SGraph)
, mMetaData :: T.Box (Maybe GET.MetaData)
, multiSelectEnabled :: T.Box Boolean
, removedNodeIds :: T.Box SigmaxT.NodeIds
, selectedNodeIds :: T.Box SigmaxT.NodeIds
, showControls :: T.Box Boolean
, sideTab :: T.Box GET.SideTab
, showSidebar :: T.Box GT.SidePanelState
}
focusedSidePanel sidePanel = do
mGraph <- T.useFocused
(maybe Nothing _.mGraph)
(\val -> maybe Nothing (\sp -> Just $ sp { mGraph = val })) sidePanel
mMetaData <- T.useFocused
(maybe Nothing _.mMetaData)
(\val -> maybe Nothing (\sp -> Just $ sp { mMetaData = val })) sidePanel
multiSelectEnabled <- T.useFocused
(maybe false _.multiSelectEnabled)
(\val -> maybe Nothing (\sp -> Just $ sp { multiSelectEnabled = val })) sidePanel
removedNodeIds <- T.useFocused
(maybe Set.empty _.removedNodeIds)
(\val -> maybe Nothing (\sp -> Just $ sp { removedNodeIds = val })) sidePanel
selectedNodeIds <- T.useFocused
(maybe Set.empty _.selectedNodeIds)
(\val -> maybe Nothing (\sp -> Just $ sp { selectedNodeIds = val })) sidePanel
showControls <- T.useFocused
(maybe false _.showControls)
(\val -> maybe Nothing (\sp -> Just $ sp { showControls = val })) sidePanel
sideTab <- T.useFocused
(maybe GET.SideTabLegend _.sideTab)
(\val -> maybe Nothing (\sp -> Just $ sp { sideTab = val })) sidePanel
showSidebar <- T.useFocused
(maybe GT.InitialClosed _.showSidebar)
(\val -> maybe Nothing (\sp -> Just $ sp { showSidebar = val })) sidePanel
pure $ {
mGraph
, mMetaData
, multiSelectEnabled
, removedNodeIds
, selectedNodeIds
, showControls
, sideTab
, showSidebar
}
module Gargantext.Components.GraphExplorer.Store
( Store
, State
, options
, context
, provide
) where
import Gargantext.Prelude
import Data.Maybe (Maybe(..))
import Data.Set as Set
import Gargantext.Components.GraphExplorer.Types as GET
import Gargantext.Hooks.Sigmax.Types as SigmaxT
import Gargantext.Types as GT
import Gargantext.Utils.Range as Range
import Gargantext.Utils.Reactix as R2
import Gargantext.Utils.Stores as Stores
import Reactix as R
import Toestand as T
import Unsafe.Coerce (unsafeCoerce)
here :: R2.Here
here = R2.here "Gargantext.Components.GraphExplorer.Store"
type Store =
-- Data
( graph :: T.Box SigmaxT.SGraph
, graphId :: T.Box GET.GraphId
, mMetaData :: T.Box (Maybe GET.MetaData)
, hyperdataGraph :: T.Box GET.HyperdataGraph
-- Layout
, showControls :: T.Box Boolean
, sideTab :: T.Box GET.SideTab
, showSidebar :: T.Box GT.SidePanelState
, showDoc :: T.Box (Maybe GET.GraphSideDoc)
-- Controls
, multiSelectEnabled :: T.Box Boolean
, edgeConfluence :: T.Box Range.NumberRange
, edgeWeight :: T.Box Range.NumberRange
, forceAtlasState :: T.Box SigmaxT.ForceAtlasState
, graphStage :: T.Box GET.Stage
, nodeSize :: T.Box Range.NumberRange
, showEdges :: T.Box SigmaxT.ShowEdgesState
, showLouvain :: T.Box Boolean
, labelSize :: T.Box Number
, mouseSelectorSize :: T.Box Number
, startForceAtlas :: T.Box Boolean
-- Terms update
, removedNodeIds :: T.Box SigmaxT.NodeIds
, selectedNodeIds :: T.Box SigmaxT.NodeIds
)
type State =
-- Data
( graph :: SigmaxT.SGraph
, graphId :: GET.GraphId
, mMetaData :: Maybe GET.MetaData
, hyperdataGraph :: GET.HyperdataGraph
-- Layout
, showControls :: Boolean
, sideTab :: GET.SideTab
, showSidebar :: GT.SidePanelState
, showDoc :: Maybe GET.GraphSideDoc
-- Controls
, multiSelectEnabled :: Boolean
, edgeConfluence :: Range.NumberRange
, edgeWeight :: Range.NumberRange
, forceAtlasState :: SigmaxT.ForceAtlasState
, graphStage :: GET.Stage
, nodeSize :: Range.NumberRange
, showEdges :: SigmaxT.ShowEdgesState
, showLouvain :: Boolean
, labelSize :: Number
, mouseSelectorSize :: Number
, startForceAtlas :: Boolean
-- Terms update
, removedNodeIds :: SigmaxT.NodeIds
, selectedNodeIds :: SigmaxT.NodeIds
)
options ::
{ labelSize :: Number
, mouseSelectorSize :: Number
, multiSelectEnabled :: Boolean
, removedNodeIds :: SigmaxT.NodeIds
, selectedNodeIds :: SigmaxT.NodeIds
, showControls :: Boolean
, showDoc :: Maybe GET.GraphSideDoc
, showSidebar :: GT.SidePanelState
, sideTab :: GET.SideTab
, edgeConfluence :: Range.NumberRange
, graphStage :: GET.Stage
, nodeSize :: Range.NumberRange
, showLouvain :: Boolean
, showEdges :: SigmaxT.ShowEdgesState
}
options =
-- Layout
{ showControls : false
, sideTab : GET.SideTabLegend
, showSidebar : GT.InitialClosed
, showDoc : Nothing
-- Controls
, multiSelectEnabled : false
, labelSize : 14.0
, mouseSelectorSize : 15.0
, edgeConfluence : Range.Closed { min: 0.0, max: 1.0 }
, graphStage : GET.Init
, nodeSize : Range.Closed { min: 0.0, max: 100.0 }
, showLouvain : false
, showEdges : SigmaxT.EShow
-- Terms update
, removedNodeIds : Set.empty
, selectedNodeIds : Set.empty
}
context :: R.Context (Record Store)
context = R.createContext $ unsafeCoerce unit
provide :: Record State -> Array R.Element -> R.Element
provide values = Stores.provideStore here.name values context
module Gargantext.Components.GraphExplorer.ToggleButton
( Props
, toggleButton
, toggleButtonCpt
, controlsToggleButton
) where
import Prelude
import Effect (Effect)
import Gargantext.Utils.Reactix as R2
import Reactix as R
import Reactix.DOM.HTML as H
import Toestand as T
-- @WIP: used?
here :: R2.Here
here = R2.here "Gargantext.Components.GraphExplorer.ToggleButton"
type Props = (
state :: T.Box Boolean
, onMessage :: String
, offMessage :: String
, style :: String
, onClick :: forall e. e -> Effect Unit
)
toggleButton :: R2.Component Props
toggleButton = R.createElement toggleButtonCpt
toggleButtonCpt :: R.Component Props
toggleButtonCpt = here.component "toggleButton" cpt
where
cpt { state
, onMessage
, offMessage
, onClick
, style } _ = do
state' <- T.useLive T.unequal state
pure $ H.div { className: "btn btn-outline-" <> style <> " " <> cls state' <> " mx-2"
, on: { click: onClick }
} [ R2.small {} [ H.text (text onMessage offMessage state') ] ]
cls true = "active"
cls false = ""
text on _off true = on
text _on off false = off
----------------------------------------------------------------
type ControlsToggleButtonProps = (
state :: T.Box 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: \_ -> T.modify_ not state
, style: "light"
} []
module Gargantext.Components.GraphExplorer.Buttons
( Props
, centerButton
, simpleButton
module Gargantext.Components.GraphExplorer.Toolbar.Buttons
( centerButton
, cameraButton
, edgesToggleButton
, louvainToggleButton
......@@ -19,7 +17,6 @@ import Data.Either (Either(..))
import Data.Enum (fromEnum)
import Data.Maybe (Maybe(..))
import Data.String as DS
import Effect (Effect)
import Effect.Aff (launchAff_)
import Effect.Class (liftEffect)
import Effect.Now as EN
......@@ -43,27 +40,10 @@ import Reactix.DOM.HTML as H
import Toestand as T
here :: R2.Here
here = R2.here "Gargantext.Components.GraphExplorer.Button"
type Props = (
onClick :: forall e. e -> Effect Unit
, text :: String
)
-- @WIP
simpleButton :: Record Props -> R.Element
simpleButton props = R.createElement simpleButtonCpt props []
here = R2.here "Gargantext.Components.GraphExplorer.Toolbar.Button"
------------------------------------------------------
simpleButtonCpt :: R.Component Props
simpleButtonCpt = here.component "simpleButton" cpt
where
cpt {onClick, text} _ = do
pure $ H.button { className: "btn btn-outline-secondary"
, on: {click: onClick}
} [ R2.small {} [ H.text text ] ]
centerButton :: R.Ref Sigmax.Sigma -> R.Element
centerButton sigmaRef = B.button
{ variant: OutlinedButtonVariant Secondary
......
This diff is collapsed.
module Gargantext.Components.GraphExplorer.RangeControl
module Gargantext.Components.GraphExplorer.Toolbar.RangeControl
( Props
, rangeControl
, edgeConfluenceControl
......@@ -16,7 +16,7 @@ import Gargantext.Utils.Range as Range
import Gargantext.Utils.Reactix as R2
here :: R2.Here
here = R2.here "Gargantext.Components.GraphExplorer.RangeControl"
here = R2.here "Gargantext.Components.GraphExplorer.Toolbar.RangeControl"
type Props =
( caption :: String
......
module Gargantext.Components.GraphExplorer.SlideButton
module Gargantext.Components.GraphExplorer.Toolbar.SlideButton
( Props
, sizeButton
, labelSizeButton
......@@ -17,7 +17,7 @@ import Gargantext.Hooks.Sigmax.Sigma as Sigma
import Gargantext.Utils.Reactix as R2
here :: R2.Here
here = R2.here "Gargantext.Components.GraphExplorer.SlideButton"
here = R2.here "Gargantext.Components.GraphExplorer.Toolbar.SlideButton"
type Props =
( caption :: String
......
module Gargantext.Components.GraphExplorer.Search
module Gargantext.Components.GraphExplorer.Topbar.Search
( Props, nodeSearchControl ) where
import Prelude
......@@ -18,10 +18,10 @@ import Reactix.DOM.HTML as H
import Toestand as T
here :: R2.Here
here = R2.here "Gargantext.Components.GraphExplorer.Search"
here = R2.here "Gargantext.Components.GraphExplorer.Topbar.Search"
type Props = (
graph :: SigmaxT.SGraph
type Props =
( graph :: SigmaxT.SGraph
, multiSelectEnabled :: T.Box Boolean
, selectedNodeIds :: T.Box SigmaxT.NodeIds
, className :: String
......
......@@ -2,42 +2,38 @@ module Gargantext.Components.GraphExplorer.TopBar (topBar) where
import Gargantext.Prelude hiding (max, min)
import Data.Maybe (Maybe)
import Gargantext.Components.Bootstrap as B
import Gargantext.Components.Bootstrap.Types (ButtonVariant(..), Variant(..))
import Gargantext.Components.GraphExplorer.Search (nodeSearchControl)
import Gargantext.Components.GraphExplorer.Sidebar.Types as GEST
import Gargantext.Components.GraphExplorer.Store as GraphStore
import Gargantext.Components.GraphExplorer.Topbar.Search (nodeSearchControl)
import Gargantext.Types as GT
import Gargantext.Utils ((?))
import Gargantext.Utils.Reactix as R2
import Gargantext.Utils.Stores as Stores
import Reactix as R
import Reactix.DOM.HTML as H
import Toestand as T
type Props =
( sidePanelGraph :: T.Box (Maybe (Record GEST.SidePanel))
)
here :: R2.Here
here = R2.here "Gargantext.Components.GraphExplorer.TopBar"
topBar :: R2.Leaf Props
topBar :: R2.Leaf ()
topBar = R2.leaf component
component :: R.Component Props
component :: R.Component ()
component = here.component "topBar" cpt where
cpt { sidePanelGraph } _ = do
cpt _ _ = do
-- States
{ mGraph
{ graph
, multiSelectEnabled
, selectedNodeIds
, showControls
, showSidebar
} <- GEST.focusedSidePanel sidePanelGraph
} <- Stores.useStore GraphStore.context
mGraph' <- R2.useLive' mGraph
showControls' <- R2.useLive' showControls
showSidebar' <- R2.useLive' showSidebar
graph' <- R2.useLive' graph
showControls' <- R2.useLive' showControls
showSidebar' <- R2.useLive' showSidebar
-- Render
pure $
......@@ -73,12 +69,10 @@ component = here.component "topBar" cpt where
]
,
-- Search
R2.fromMaybe_ mGraph' \graph ->
nodeSearchControl
{ graph
, multiSelectEnabled
, selectedNodeIds
, className: "graph-topbar__search"
}
nodeSearchControl
{ graph: graph'
, multiSelectEnabled
, selectedNodeIds
, className: "graph-topbar__search"
}
]
module Gargantext.Components.GraphExplorer.Types where
import Gargantext.Prelude
import Data.Array ((!!), length)
import Data.Generic.Rep (class Generic)
import Data.Eq.Generic (genericEq)
import Data.Maybe (Maybe(..), fromJust)
import Data.Newtype (class Newtype)
import Data.Ord
import Data.Ord.Generic (genericCompare)
import Data.Symbol (SProxy(..))
import Partial.Unsafe (unsafePartial)
import Record as Record
import Simple.JSON as JSON
import Gargantext.Prelude
type GraphId = Int
newtype Node = Node {
......@@ -99,6 +98,7 @@ type ListId = Int
type Version = Int
type CorpusId = Int
type CorpusLabel = String
type DocId = Int
newtype GraphSideCorpus = GraphSideCorpus
{ corpusId :: CorpusId
......@@ -108,6 +108,14 @@ newtype GraphSideCorpus = GraphSideCorpus
derive instance Generic GraphSideCorpus _
instance Eq GraphSideCorpus where eq = genericEq
newtype GraphSideDoc = GraphSideDoc
{ docId :: DocId
, corpusId :: CorpusId
, listId :: ListId
}
derive instance Generic GraphSideDoc _
instance Eq GraphSideDoc where eq = genericEq
newtype GraphData = GraphData
{ nodes :: Array Node
, edges :: Array Edge
......@@ -164,7 +172,7 @@ instance Ord SelectedNode where compare = genericCompare
instance Show SelectedNode where show (SelectedNode node) = node.label
type State = (
-- type State = (
-- corpusId :: R.State Int
--, filePath :: R.State String
--, graphData :: R.State GraphData
......@@ -177,7 +185,7 @@ type State = (
--, sigmaGraphData :: R.State (Maybe SigmaxTypes.SGraph)
--, sigmaSettings :: R.State ({|Graph.SigmaSettings})
--treeId :: R.State (Maybe TreeId)
)
-- )
initialGraphData :: GraphData
initialGraphData = GraphData {
......@@ -255,3 +263,7 @@ instance JSON.ReadForeign HyperdataGraph where
pure $ HyperdataGraph $ Record.rename cameraP mCameraP inst
instance JSON.WriteForeign HyperdataGraph where
writeImpl (HyperdataGraph c) = JSON.writeImpl $ Record.rename mCameraP cameraP c
data Stage = Init | Ready | Cleanup
derive instance Generic Stage _
derive instance Eq Stage
......@@ -10,7 +10,7 @@ import Gargantext.Utils.Reactix as R2
here :: R2.Here
here = R2.here "Gargantext.Components.InputWithEnter"
type Props a =
type Props =
( onBlur :: String -> Effect Unit
, onEnter :: Unit -> Effect Unit
, onValueChanged :: String -> Effect Unit
......@@ -22,12 +22,9 @@ type Props a =
, type :: String
)
type PropsKey a =
( key :: String
| Props a )
inputWithEnterWithKey :: forall a. R2.Leaf (PropsKey a)
inputWithEnterWithKey :: R2.Leaf ( key :: String | Props )
inputWithEnterWithKey = R2.leafComponent inputWithEnterWithKeyCpt
inputWithEnterWithKeyCpt :: R.Component ( key :: String | Props )
inputWithEnterWithKeyCpt = here.component "inputWithEnterWithKey" cpt where
cpt { onBlur, onEnter, onValueChanged, autoFocus, className, defaultValue, placeholder, type: t } _ = do
pure $ inputWithEnter { onBlur
......@@ -39,9 +36,9 @@ inputWithEnterWithKeyCpt = here.component "inputWithEnterWithKey" cpt where
, placeholder
, type: t }
inputWithEnter :: forall a. R2.Leaf (Props a)
inputWithEnter :: R2.Leaf Props
inputWithEnter = R2.leafComponent inputWithEnterCpt
inputWithEnterCpt :: forall a. R.Component (Props a)
inputWithEnterCpt :: R.Component Props
inputWithEnterCpt = here.component "inputWithEnter" cpt
where
cpt props@{ onBlur, onEnter, onValueChanged
......@@ -65,4 +62,3 @@ inputWithEnterCpt = here.component "inputWithEnter" cpt
onEnter unit
else
pure unit
......@@ -128,8 +128,8 @@ listTreeChildrenCpt = here.component "listTreeChildren" cpt where
, session } [] }
where
errorHandler err = case err of
ReadJSONError err' -> here.log2 "[listTreeChildren] ReadJSONError" $ show err'
_ -> here.log2 "[listTreeChildren] RESTError" err
ReadJSONError err' -> here.warn2 "[listTreeChildren] ReadJSONError" $ show err'
_ -> here.warn2 "[listTreeChildren] RESTError" err
type ListTreeChildrenLoadedProps =
( loaded :: Array NodeSimple
......
......@@ -125,7 +125,7 @@ clearCacheButton =
launchAff_
$ GHL.clearCache unit
*> NTL.clearCache unit
*> liftEffect (here.log "cache cleared")
*> liftEffect (here.info "cache cleared")
renderBackend :: forall b. T.Write b (Maybe Backend) => b -> Backend -> R.Element
renderBackend cursor backend@(Backend {name, baseUrl, backendType}) =
......
......@@ -26,13 +26,13 @@ here :: R2.Here
here = R2.here "Gargantext.Components.NgramsTable.Components"
type SearchInputProps =
( key :: String -- to prevent refreshing & losing input
, searchQuery :: T.Box String
( searchQuery :: T.Box String
)
searchInput :: R2.Leaf SearchInputProps
-- "key": to prevent refreshing & losing input
searchInput :: R2.Leaf ( key :: String | SearchInputProps )
searchInput = R2.leafComponent searchInputCpt
searchInputCpt :: R.Component SearchInputProps
searchInputCpt :: R.Component ( key :: String | SearchInputProps )
searchInputCpt = here.component "searchInput" cpt
where
cpt { searchQuery } _ = do
......@@ -55,7 +55,7 @@ searchButtonCpt :: R.Component SearchButtonProps
searchButtonCpt = here.component "searchButton" cpt where
cpt { searchQuery } _ = do
searchQuery' <- T.useLive T.unequal searchQuery
pure $ H.div { className: "input-group-prepend" }
[ if searchQuery' /= ""
then
......@@ -75,7 +75,7 @@ searchFieldInputCpt :: R.Component SearchFieldInputProps
searchFieldInputCpt = here.component "searchFieldInput" cpt where
cpt { searchQuery } _ = do
-- searchQuery' <- T.useLive T.unequal searchQuery
pure $ H.input { className: "form-control"
-- , defaultValue: searchQuery'
, name: "search"
......@@ -83,7 +83,7 @@ searchFieldInputCpt = here.component "searchFieldInput" cpt where
, placeholder: "Search"
, type: "value"
}
type SelectionCheckboxProps =
( allNgramsSelected :: Boolean
, dispatch :: Dispatch
......
......@@ -73,11 +73,6 @@ type LayoutProps = WithSession LayoutNoSessionProps
type LayoutSessionContextProps = WithSessionContext LayoutNoSessionProps
type KeyLayoutProps = (
key :: String
| LayoutProps
)
userLayout :: R2.Component LayoutProps
userLayout = R.createElement userLayoutCpt
userLayoutCpt :: R.Component LayoutProps
......@@ -89,9 +84,9 @@ userLayoutCpt = here.component "userLayout" cpt
pure $ userLayoutWithKey $ Record.merge props { key: show sid <> "-" <> show nodeId }
userLayoutWithKey :: R2.Leaf KeyLayoutProps
userLayoutWithKey :: R2.Leaf ( key :: String | LayoutProps )
userLayoutWithKey = R2.leafComponent userLayoutWithKeyCpt
userLayoutWithKeyCpt :: R.Component KeyLayoutProps
userLayoutWithKeyCpt :: R.Component ( key :: String | LayoutProps )
userLayoutWithKeyCpt = here.component "userLayoutWithKey" cpt where
cpt { boxes: boxes@{ sidePanelTexts }
, frontends
......
......@@ -117,7 +117,7 @@ contactInfoItemCpt = here.component "contactInfoItem" cpt
]
where
cLens = L.cloneLens lens
type ItemProps =
( defaultVal :: String
, isEditing :: T.Box Boolean
......@@ -133,7 +133,7 @@ itemNotEditingCpt :: R.Component ItemProps
itemNotEditingCpt = here.component "itemEditing" cpt where
cpt { isEditing, valueBox } _ = do
valueBox' <- T.useLive T.unequal valueBox
pure $ H.div { className: "input-group col-sm-6" }
[ H.input
{ className: "form-control", type: "text"
......@@ -183,12 +183,8 @@ type ReloadProps =
type LayoutProps =
( session :: Session
| ReloadProps )
type KeyLayoutProps =
( key :: String
, session :: Session
| ReloadProps )
| ReloadProps
)
saveContactHyperdata :: Session -> Int -> HyperdataContact -> AffRESTError Int
saveContactHyperdata session id = put session (Routes.NodeAPI Node (Just id) "")
......@@ -218,9 +214,17 @@ saveUserInfo session id ui = do
ga (Just val) = ArgR val
getToken (Session { token }) = token
type AnnuaireLayoutProps = ( annuaireId :: Int, session :: Session | ReloadProps )
type AnnuaireLayoutProps =
( annuaireId :: Int
, session :: Session
| ReloadProps
)
type AnnuaireKeyLayoutProps = ( annuaireId :: Int | KeyLayoutProps )
type AnnuaireKeyLayoutProps =
( annuaireId :: Int
, key :: String
| LayoutProps
)
contactLayout :: R2.Component AnnuaireLayoutProps
contactLayout = R.createElement contactLayoutCpt
......
......@@ -345,12 +345,12 @@ changeCode onc (JSON j) CE.Python _ = onc $ Python $ defaultPython' { python = t
toCode = R2.stringify (JSON.writeImpl j) 2
changeCode onc _ CE.JSON c = do
case JSON.readJSON c of
Left err -> here.log2 "[fieldCodeEditor'] cannot parse json" c -- TODO Refactor?
Left err -> here.warn2 "[fieldCodeEditor'] cannot parse json" c -- TODO Refactor?
Right j' -> onc $ JSON j'
-- case jsonParser c of
-- Left err -> here.log2 "[fieldCodeEditor'] cannot parse json" c
-- Left err -> here.warn2 "[fieldCodeEditor'] cannot parse json" c
-- Right j' -> case decodeJson j' of
-- Left err -> here.log2 "[fieldCodeEditor'] cannot decode json" j'
-- Left err -> here.warn2 "[fieldCodeEditor'] cannot decode json" j'
-- Right j'' -> onc $ JSON j''
changeCode onc (JSON j) CE.Markdown _ = onc $ Markdown $ defaultMarkdown' { text = text }
where
......
......@@ -50,7 +50,7 @@ metricsLoadViewCpt = here.component "metricsLoadView" cpt
where
errorHandler error = do
T.modify_ (A.cons $ FRESTError { error }) errors
here.log2 "RESTError" error
here.warn2 "RESTError" error
type MetricsWithCacheLoadViewProps res ret =
( getMetricsHash :: Session -> ReloadPath -> AffRESTError Hash
......
......@@ -141,7 +141,7 @@ corpusCodeViewCpt = here.component "corpusCodeView" cpt where
, session }
liftEffect $ do
_ <- case res of
Left err -> here.log2 "[corpusLayoutView] onClickSave RESTError" err
Left err -> here.warn2 "[corpusLayoutView] onClickSave RESTError" err
_ -> pure unit
T2.reload reload
......
......@@ -79,7 +79,7 @@ dashboardLayoutWithKeyCpt = here.component "dashboardLayoutWithKey" cpt
, session }
liftEffect $ do
_ <- case res of
Left err -> here.log2 "[dashboardLayoutWithKey] onChange RESTError" err
Left err -> here.warn2 "[dashboardLayoutWithKey] onChange RESTError" err
_ -> pure unit
T2.reload reload
......
module Gargantext.Components.Nodes.Corpus.Graph.Tabs where
import Prelude hiding (div)
import Data.Array (fromFoldable)
import Data.Tuple (Tuple(..))
import Reactix as R
import Toestand as T
import Gargantext.Components.GraphExplorer.Types (GraphSideCorpus(..))
import Gargantext.Components.FacetsTable (docView)
import Gargantext.Components.Search (SearchQuery)
import Gargantext.Components.Table as Table
import Gargantext.Components.Tab as Tab
import Gargantext.Ends (Frontends)
import Gargantext.Sessions (Session)
import Gargantext.Utils.Reactix as R2
here :: R2.Here
here = R2.here "Gargantext.Components.Nodes.Corpus.Graph.Tabs"
type Props =
( frontends :: Frontends
, query :: SearchQuery
, session :: Session
, sides :: Array GraphSideCorpus
)
tabs :: Record Props -> R.Element
tabs props = R.createElement tabsCpt props []
-- TODO no need for Children here
tabsCpt :: R.Component Props
tabsCpt = here.component "tabs" cpt
where
cpt {frontends, query, session, sides} _ = do
activeTab <- T.useBox 0
pure $ Tab.tabs { activeTab, tabs: tabs' }
where
tabs' = fromFoldable $ tab frontends session query <$> sides
tab :: Frontends -> Session -> SearchQuery -> GraphSideCorpus -> Tuple String R.Element
tab frontends session query (GraphSideCorpus {corpusId: nodeId, corpusLabel, listId}) =
Tuple corpusLabel (docView dvProps)
where
dvProps = {frontends, session, nodeId, listId, query, chart, totalRecords: 0, container}
chart = mempty
container = Table.graphContainer
......@@ -5,25 +5,27 @@ module Gargantext.Components.Nodes.Corpus.Graph
import Gargantext.Prelude
import DOM.Simple (document, querySelector)
import Data.Maybe (Maybe(..), isJust)
import Data.Set as Set
import Data.Int as I
import Data.Maybe (Maybe(..), isJust, maybe)
import Data.Sequence as Seq
import Data.Tuple (Tuple(..))
import Data.Tuple.Nested ((/\))
import Gargantext.Components.App.Data (Boxes)
import Gargantext.Components.Bootstrap as B
import Gargantext.Components.GraphExplorer.API as GraphAPI
import Gargantext.Components.GraphExplorer.Layout (convert, layout)
import Gargantext.Components.GraphExplorer.Store as GraphStore
import Gargantext.Components.GraphExplorer.Types as GET
import Gargantext.Config.REST (AffRESTError, logRESTError)
import Gargantext.Config.REST (logRESTError)
import Gargantext.Hooks.Loader (useLoaderEffect)
import Gargantext.Hooks.Sigmax as Sigmax
import Gargantext.Hooks.Sigmax.Types as SigmaxT
import Gargantext.Routes (SessionRoute(NodeAPI))
import Gargantext.Sessions (Session, get)
import Gargantext.Types as Types
import Gargantext.Sessions (Session)
import Gargantext.Utils.Range as Range
import Gargantext.Utils.Reactix as R2
import Gargantext.Utils.Toestand as T2
import Reactix as R
import Reactix.DOM.HTML as H
import Toestand as T
import Record as Record
type Props =
......@@ -42,20 +44,17 @@ graphLayout = R2.leaf graphLayoutCpt
graphLayoutCpt :: R.Component Props
graphLayoutCpt = here.component "explorerLayout" cpt where
cpt props@{ boxes: { graphVersion }, graphId, session } _ = do
-- | States
-- |
graphVersion' <- T.useLive T.unequal graphVersion
graphVersion' <- R2.useLive' graphVersion
state' /\ state <- R2.useBox' Nothing
-- | Hooks
-- |
useLoaderEffect
{ errorHandler
, loader: getNodes session graphVersion'
, loader: GraphAPI.getNodes session graphVersion'
, path: graphId
, state
}
......@@ -119,20 +118,20 @@ graphLayoutCpt = here.component "explorerLayout" cpt where
where
errorHandler = logRESTError here "[explorerLayout]"
handler loaded@(GET.HyperdataGraph { graph: hyperdataGraph }) =
content { graph
initGraph { graph
, hyperdataGraph: loaded
, mMetaData'
, mMetaData
, session
, boxes: props.boxes
, graphId
}
where
Tuple mMetaData' graph = convert hyperdataGraph
Tuple mMetaData graph = convert hyperdataGraph
--------------------------------------------------------
type ContentProps =
( mMetaData' :: Maybe GET.MetaData
type InitGraphProps =
( mMetaData :: Maybe GET.MetaData
, graph :: SigmaxT.SGraph
, hyperdataGraph :: GET.HyperdataGraph
, session :: Session
......@@ -140,38 +139,62 @@ type ContentProps =
, graphId :: GET.GraphId
)
content :: R2.Leaf ContentProps
content = R2.leaf contentCpt
contentCpt :: R.Component ContentProps
contentCpt = here.component "content" cpt where
cpt props@{ boxes, mMetaData', graph } _ = do
-- Hooks
R.useEffectOnce' $
-- Hydrate Boxes
flip T.write_ boxes.sidePanelGraph $ Just
{ mGraph: Just graph
, mMetaData: mMetaData'
, multiSelectEnabled: false
, removedNodeIds: Set.empty
, selectedNodeIds: Set.empty
, showControls: false
, sideTab: GET.SideTabLegend
, showSidebar: Types.InitialClosed
}
initGraph :: R2.Leaf InitGraphProps
initGraph = R2.leaf initGraphCpt
initGraphCpt :: R.Component InitGraphProps
initGraphCpt = here.component "initGraph" cpt where
cpt { boxes
, mMetaData
, graph
, graphId
, session
, hyperdataGraph
} _ = do
-- | Computed
-- |
let
startForceAtlas = maybe true
(\(GET.MetaData { startForceAtlas: sfa }) -> sfa) mMetaData
-- Render
forceAtlasState
= if startForceAtlas
then SigmaxT.InitialRunning
else SigmaxT.InitialStopped
pure $
-- | Hooks
-- |
sigmaRef <- Sigmax.initSigma >>= R.useRef
-- Hydrate GraphStore
(state :: Record GraphStore.State) <- pure $
-- Data
{ graph
, graphId
, mMetaData
, hyperdataGraph
-- Controls
, startForceAtlas
, forceAtlasState
, edgeWeight: Range.Closed
{ min: 0.0
, max: I.toNumber $ Seq.length $ SigmaxT.graphEdges graph
}
-- (default options)
} `Record.merge` GraphStore.options
layout
props
-- | Render
-- |
--------------------------------------------------------------
pure $
getNodes :: Session -> T2.Reload -> GET.GraphId -> AffRESTError GET.HyperdataGraph
getNodes session graphVersion graphId =
get session $ NodeAPI Types.Graph
(Just graphId)
("?version=" <> (show graphVersion))
GraphStore.provide
state
[
layout
{ session
, boxes
, sigmaRef
}
]
......@@ -45,13 +45,9 @@ listsLayoutCpt = here.component "listsLayout" cpt where
let sid = sessionId session
pure $ listsLayoutWithKey (Record.merge props { key: show sid <> "-" <> show nodeId }) []
type KeyProps =
( key :: String
| Props )
listsLayoutWithKey :: R2.Component KeyProps
listsLayoutWithKey :: R2.Component ( key :: String | Props )
listsLayoutWithKey = R.createElement listsLayoutWithKeyCpt
listsLayoutWithKeyCpt :: R.Component KeyProps
listsLayoutWithKeyCpt :: R.Component ( key :: String | Props )
listsLayoutWithKeyCpt = here.component "listsLayoutWithKey" cpt where
cpt { boxes: boxes@{ reloadMainPage }
, nodeId
......
......@@ -38,11 +38,9 @@ type Props = (
, session :: Session
)
type PropsWithKey = ( key :: String | Props )
tabs :: Record PropsWithKey -> R.Element
tabs :: Record ( key :: String | Props ) -> R.Element
tabs props = R.createElement tabsCpt props []
tabsCpt :: R.Component PropsWithKey
tabsCpt :: R.Component ( key :: String | Props )
tabsCpt = here.component "tabs" cpt where
cpt props@{ activeTab } _ = do
pure $ Tab.tabs { activeTab
......
......@@ -32,13 +32,13 @@ import Gargantext.Components.Tile (tileBlock)
import Gargantext.Components.TopBar as TopBar
import Gargantext.Config (defaultFrontends, defaultBackends)
import Gargantext.Ends (Backend)
import Gargantext.Hooks.FirstEffect (useFirstEffect)
import Gargantext.Hooks.Resize (ResizeType(..), useResizeHandler)
import Gargantext.Routes (AppRoute, Tile)
import Gargantext.Routes as GR
import Gargantext.Sessions (Session, WithSession)
import Gargantext.Sessions as Sessions
import Gargantext.Types (CorpusId, Handed(..), ListId, NodeID, NodeType(..), SessionId, SidePanelState(..))
import Gargantext.Utils ((?))
import Gargantext.Utils.Reactix (getElementById)
import Gargantext.Utils.Reactix as R2
import Reactix as R
......@@ -63,11 +63,10 @@ router :: R2.Leaf Props
router = R2.leafComponent routerCpt
routerCpt :: R.Component Props
routerCpt = here.component "router" cpt where
cpt { boxes: boxes@{ handed, showLogin, showTree } } _ = do
cpt { boxes: boxes@{ handed, showLogin } } _ = do
-- States
handed' <- R2.useLive' handed
showLogin' <- R2.useLive' showLogin
showTree' <- R2.useLive' showTree
-- Effects
let
......@@ -100,11 +99,7 @@ routerCpt = here.component "router" cpt where
[
-- @XXX: ReactJS lack of "keep-alive" feature workaround solution
-- @link https://github.com/facebook/react/issues/12039
-- ↓
-- @XXX: ReactJS "display: none" don't exec effect cleaning function
-- (therefore cannot use the simple "display: none" workaround
-- to keep below component alive)
R2.if' (showTree') $ forest { boxes }
forest { boxes }
,
mainPage { boxes }
,
......@@ -209,14 +204,18 @@ mainPageCpt = here.component "mainPage" cpt where
forest :: R2.Leaf Props
forest = R2.leaf forestCpt
forestCpt :: R.Memo Props
forestCpt = R.memo' $ here.component "forest" cpt where
cpt { boxes } _ = do
-- States
showTree' <- R2.useLive' boxes.showTree
-- Hooks
resizeHandler <- useResizeHandler
-- Effects
useFirstEffect do
R.useLayoutEffect1' [] do
resizeHandler.add ".router__handle__action" ".router__aside" Vertical
pure $ resizeHandler.remove ".router__handle__action"
......@@ -224,7 +223,11 @@ forestCpt = R.memo' $ here.component "forest" cpt where
pure $
H.div
{ className: "router__aside" }
{ className: intercalate " "
[ "router__aside"
, showTree' ? "" $ "d-none"
]
}
[
forestLayout
{ boxes
......@@ -267,9 +270,10 @@ type RenderRouteProps =
)
renderRoute :: R2.Leaf RenderRouteProps
renderRoute = R2.leafComponent renderRouteCpt
renderRouteCpt :: R.Component RenderRouteProps
renderRouteCpt = here.component "renderRoute" cpt where
renderRoute = R2.leaf renderRouteCpt
renderRouteCpt :: R.Memo RenderRouteProps
renderRouteCpt = R.memo' $ here.component "renderRoute" cpt where
cpt { boxes, route } _ = do
let sessionNodeProps sId nId =
{ nodeId: nId
......
......@@ -23,9 +23,8 @@ type DocID = Int
thisModule :: String
thisModule = "Gargantext.Components.Score"
type Props = (
docId ::DocID
, key :: String
type Props =
( docId ::DocID
, nodeId :: GT.NodeID
, score :: Maybe Score
, session :: Session
......@@ -34,9 +33,9 @@ type Props = (
type Choice = Maybe Score
scoreEl :: R2.Component Props
scoreEl :: R2.Component ( key :: String | Props )
scoreEl = R.createElement scoreElCpt
scoreElCpt :: R.Component Props
scoreElCpt :: R.Component ( key :: String | Props )
scoreElCpt = R.hooksComponentWithModule thisModule "scoreEl" cpt
where
cpt { docId, nodeId, score, session, tableReload } _ = do
......
......@@ -77,7 +77,6 @@ type TableHeaderWithRenameBoxedLayoutProps = (
, nodeId :: NodeID
, name :: String
, date :: String
, key :: String
, corpusInfoS :: T.Box CorpusInfo
)
......@@ -91,11 +90,11 @@ tableHeaderWithRenameLayout = R.createElement tableHeaderWithRenameLayoutCpt
tableHeaderWithRenameLayoutCpt :: R.Component TableHeaderWithRenameLayoutProps
tableHeaderWithRenameLayoutCpt = here.component "tableHeaderWithRenameLayoutCpt" cpt
where
cpt { hyperdata: Hyperdata h, nodeId, session, cacheState, name, date, key } _ = do
cpt { hyperdata: Hyperdata h, nodeId, session, cacheState, name, date } _ = do
let corpusInfo = getCorpusInfo h.fields
corpusInfoS <- T.useBox corpusInfo
pure $ tableHeaderWithRenameBoxedLayout {hyperdata: Hyperdata h, nodeId, session, cacheState, name, date, corpusInfoS, key} []
pure $ tableHeaderWithRenameBoxedLayout {hyperdata: Hyperdata h, nodeId, session, cacheState, name, date, corpusInfoS} []
tableHeaderWithRenameBoxedLayout :: R2.Component TableHeaderWithRenameBoxedLayoutProps
tableHeaderWithRenameBoxedLayout = R.createElement tableHeaderWithRenameBoxedLayoutCpt
......@@ -117,30 +116,30 @@ tableHeaderWithRenameBoxedLayoutCpt = here.component "tableHeaderWithRenameBoxed
]
, R2.row
[ H.div {className: "col-md-8 content"}
[ H.p {}
[ H.div {}
[
renameable {icon: "fa fa-info", text: title, onRename: onRenameTitle} []
]
, H.p {}
, H.div {}
[
renameable {icon: "fa fa-globe", text: desc, onRename: onRenameDesc} []
]
, H.p {}
[
, H.div {}
[
renameable {icon: "fa fa-search-plus", text: query, onRename: onRenameQuery} []
]
, H.p { className: "cache-toggle"
, H.div { className: "cache-toggle"
, on: { click: cacheClick cacheState } }
[ H.span { className: "fa " <> (cacheToggle cacheState') } []
, H.text $ cacheText cacheState'
]
]
, H.div {className: "col-md-4 content"}
[ H.p {}
[
[ H.div {}
[
renameable {icon: "fa fa-user", text: authors, onRename: onRenameAuthors} []
]
, H.p {}
, H.div {}
[ H.span {className: "fa fa-calendar"} []
, H.text $ " " <> date
]
......@@ -188,14 +187,14 @@ tableHeaderWithRenameBoxedLayoutCpt = here.component "tableHeaderWithRenameBoxed
cacheStateToggle NT.CacheOn = NT.CacheOff
cacheStateToggle NT.CacheOff = NT.CacheOn
save :: {fields :: FTFieldList, session :: Session, nodeId :: Int} -> Effect Unit
save {fields, session, nodeId} = do
launchAff_ do
res <- saveCorpus $ {hyperdata: Hyperdata {fields}, session, nodeId}
liftEffect $ do
_ <- case res of
Left err -> here.log2 "[corpusLayoutView] onClickSave RESTError" err
Left err -> here.warn2 "[corpusLayoutView] onClickSave RESTError" err
_ -> pure unit
pure unit
......@@ -205,7 +204,7 @@ saveCorpusName {name, session, nodeId} = do
res <- rename session nodeId $ RenameValue {text: name}
liftEffect $ do
_ <- case res of
Left err -> here.log2 "[corpusLayoutView] onClickSave RESTError" err
Left err -> here.warn2 "[corpusLayoutView] onClickSave RESTError" err
_ -> pure unit
pure unit
......
......@@ -45,9 +45,9 @@ instance Eq RESTError where
eq _ _ = false
logRESTError :: R2.Here -> String -> RESTError -> Effect Unit
logRESTError here prefix (SendResponseError e) = here.log2 (prefix <> " SendResponseError ") e -- TODO: No show
logRESTError here prefix (ReadJSONError e) = here.log2 (prefix <> " ReadJSONError ") $ show e
logRESTError here prefix (CustomError e) = here.log2 (prefix <> " CustomError ") $ e
logRESTError here prefix (SendResponseError e) = here.warn2 (prefix <> " SendResponseError ") e -- TODO: No show
logRESTError here prefix (ReadJSONError e) = here.warn2 (prefix <> " ReadJSONError ") $ show e
logRESTError here prefix (CustomError e) = here.warn2 (prefix <> " CustomError ") $ e
type AffRESTError a = Aff (Either RESTError a)
......
......@@ -24,7 +24,7 @@ handleRESTError :: forall a.
-> Aff Unit
handleRESTError errors (Left error) _ = liftEffect $ do
T.modify_ (A.cons $ FRESTError { error }) errors
here.log2 "[handleTaskError] RESTError" error
here.warn2 "[handleTaskError] RESTError" error
handleRESTError _ (Right task) handler = handler task
handleErrorInAsyncProgress :: T.Box (Array FrontendError)
......
......@@ -41,8 +41,8 @@ function add(window, document, sourceQuery, targetQuery, type) {
* @param {Document} document
* @param {String} sourceQuery
*/
function remove(sourceQuery) {
function remove(document, sourceQuery) {
var source = document.querySelector(sourceQuery);
console.log(sourceQuery)
source.removeEventListener('mousedown');
}
This diff is collapsed.
......@@ -78,7 +78,7 @@ let sigmaMouseSelector = (sigma, options) => {
s.bind('kill', () => _self.unbindAll());
this.unbindAll = () => {
console.log('[sigmaMouseSelector] unbinding');
// console.log('[sigmaMouseSelector] unbinding');
_container.onclick = null;
_context.canvas.onmousemove = null;
_container.onmousedown = null;
......
"use strict";
/**
* Get Creation Date
* @return {string}
*/
exports.getCreationDate = function() {
return new Date().toLocaleTimeString()
}
This diff is collapsed.
......@@ -2,7 +2,7 @@
var API = require('../../src/external-deps/JitsiMeetAPI.js');
console.log('API', API);
// console.log('API', API);
exports._api = API;
exports._jitsiMeetAPI = function(host, options) {
......
......@@ -24,6 +24,8 @@ import Effect.Class (liftEffect)
import Effect.Exception (error)
import Effect.Uncurried (EffectFn1, EffectFn3, mkEffectFn1, mkEffectFn2, runEffectFn1, runEffectFn3)
import FFI.Simple (applyTo, args2, args3, defineProperty, delay, getProperty, (..), (...), (.=))
import Gargantext.Utils.Console (RowConsole)
import Gargantext.Utils.Console as Console
import Partial.Unsafe (unsafePartial)
import React (class ReactPropFields, Children, ReactClass, ReactElement)
import React as React
......@@ -88,16 +90,29 @@ type Module = String
type Here =
{ component :: forall p. String -> R.HooksComponent p -> R.Component p
, log :: forall l. l -> Effect Unit
, log2 :: forall l. String -> l -> Effect Unit
, ntComponent :: forall p. String -> NTHooksComponent p -> NTComponent p }
, ntComponent :: forall p. String -> NTHooksComponent p -> NTComponent p
, name :: Module
| RowConsole
}
here :: Module -> Here
here mod =
{ component: R.hooksComponentWithModule mod
, log: log2 ("[" <> mod <> "]")
, log2: \msg -> log2 ("[" <> mod <> "] " <> msg)
, ntComponent: ntHooksComponentWithModule mod }
{ component : R.hooksComponentWithModule mod
, ntComponent : ntHooksComponentWithModule mod
, name : mod
, log : Console.print Console.Main mod Console.Log
, log2 : Console.print2 Console.Main mod Console.Log
, log3 : Console.print3 Console.Main mod Console.Log
, error : Console.print Console.Main mod Console.Error
, error2 : Console.print2 Console.Main mod Console.Error
, error3 : Console.print3 Console.Main mod Console.Error
, warn : Console.print Console.Main mod Console.Warn
, warn2 : Console.print2 Console.Main mod Console.Warn
, warn3 : Console.print3 Console.Main mod Console.Warn
, info : Console.print Console.Main mod Console.Info
, info2 : Console.print2 Console.Main mod Console.Info
, info3 : Console.print3 Console.Main mod Console.Info
}
-- newtypes
type NTHooksComponent props = props -> Array R.Element -> R.Hooks R.Element
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -47,6 +47,7 @@ $knob-size: 14px
width: inherit
height: inherit
border-radius: $range-radius
border: 1px solid $range-border-color
&__knob
@include unselectable
......
This diff is collapsed.
This diff is collapsed.
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