Commit 445858fc authored by Przemyslaw Kaminski's avatar Przemyslaw Kaminski

Merge branch 'dev' into 228-doc-annotation-multiterms

parents c3987256 95d4771f
...@@ -12,14 +12,21 @@ ...@@ -12,14 +12,21 @@
bundle.js bundle.js
# tempfiles # tempfiles
.#* .#*
# webpack splays purescript modules in dist. we don't want these to be # # webpack splays purescript modules in dist. we don't want these to be
# added, but we do want static assets to be added # # added, but we do want static assets to be added
/dist/* # /dist/*
!/dist/styles/ # !/dist/styles/
/dist/styles/*map # /dist/styles/*map
!/dist/examples/ # !/dist/examples/
!/dist/fonts/ # !/dist/fonts/
!/dist/images/ # !/dist/images/
!/dist/js/ # !/dist/js/
# css source maps # # css source maps
/dist/styles/*map # /dist/styles/*map
# production builds
/prod
/dce-output
/app.js
# docker
/.bash_history
/.lesshst
FROM debian:stable-slim
ENV CWD=/opt/app HOME=/opt/app TERM=xterm
RUN apt-get update && apt-get install -y bash curl inotify-tools git build-essential libtinfo5
RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
RUN echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list
RUN apt-get update && apt-get install -y yarn
RUN curl -L https://github.com/coot/zephyr/releases/download/v0.3.2/Linux.tar.gz | tar zx -C /usr/bin --strip-components=1 zephyr/zephyr
WORKDIR /opt/app
EXPOSE 5000/tcp
CMD ["bash"]
\ No newline at end of file
...@@ -14,14 +14,47 @@ granted access to a [backend](https://gitlab.iscpif.fr/gargantext/haskell-gargan ...@@ -14,14 +14,47 @@ granted access to a [backend](https://gitlab.iscpif.fr/gargantext/haskell-gargan
This software is free software, developed by the CNRS Complex Systems This software is free software, developed by the CNRS Complex Systems
Institute of Paris Île-de-France (ISC-PIF) and its partners. Institute of Paris Île-de-France (ISC-PIF) and its partners.
## Dependencies ## Getting set up
There are two approaches to working with the build:
1. Use our docker setup
2. Install our dependencies yourself
The javascript ecosystem kind of assumes if you're on linux, you're
running on debian or ubuntu. I haven't yet managed to get garg to
build on alpine linux, for example. If you're on an oddball system, I
*strongly* recommend you just use the docker setup.
### Docker setup
You will need docker and docker-compose installed.
First, Source our environment file:
```shell
source ./env.sh
```
WARNING: you must `source ./env.sh` before using the docker
container. If you don't do that, the container will write files as
root and you'll need root powers to get ownership back!
Now build the docker image:
```shell
docker-compose build frontend
```
That's it, skip ahead to "Development".
### Manual setup
The build requires the following system dependencies preinstalled: The build requires the following system dependencies preinstalled:
* NodeJS (11+) * NodeJS (11+)
* Yarn (Recent) * Yarn (Recent)
### NodeJS #### NodeJS
On debian testing, debian unstable or ubuntu: On debian testing, debian unstable or ubuntu:
...@@ -55,7 +88,7 @@ brew install node ...@@ -55,7 +88,7 @@ brew install node
For other platforms, please refer to [the nodejs website](https://nodejs.org/en/download/). For other platforms, please refer to [the nodejs website](https://nodejs.org/en/download/).
### Yarn (javascript package manager) #### Yarn (javascript package manager)
On debian or ubuntu: On debian or ubuntu:
...@@ -75,63 +108,89 @@ For other platforms, please refer to [the yarn website](https://www.yarnpkg.com/ ...@@ -75,63 +108,89 @@ For other platforms, please refer to [the yarn website](https://www.yarnpkg.com/
## Development ## Development
Once you have node and yarn installed, you may install deps with: ### Docker environment
Are you using the docker setup? Run this:
```shell
source ./env.sh
```
This enables the docker container to run as the current user so any
files it writes will be readable by you. It also creates a `darn`
shell alias (short for `docker yarn`) for running yarn commands inside
the docker container.
### Basic tasks
Now we must install our javascript and purescript dependencies:
```shell ```shell
yarn install -D && yarn install-ps darn install -D && darn install-ps # for docker setup
yarn install -D && yarn install-ps # for manual setup
``` ```
You will likely want to check your work in a browser. We provide a You will likely want to check your work in a browser. We provide a
local development webserver that serves on port 5000 for this purpose: local development webserver that serves on port 5000 for this purpose:
```shell ```shell
yarn server darn server # for docker setup
yarn server # for manual setup
``` ```
To generate a new browser bundle to test: To generate a new browser bundle to test:
```shell ```shell
yarn build darn build # for docker setup
yarn build # for manual setup
``` ```
If you are rapidly iterating and just want to type check your code: If you are rapidly iterating and just want to type check your code:
```shell ```shell
yarn compile darn compile # for docker setup
yarn compile # for manual setup
``` ```
You may access a purescript repl if you want to explore: You may access a purescript repl if you want to explore:
```shell ```shell
yarn repl darn repl # for docker setup
yarn repl # for manual setup
``` ```
If you need to reinstall dependencies such as after a git pull or branch switch: If you need to reinstall dependencies such as after a git pull or branch switch:
```shell ```shell
yarn install -D && yarn install-ps # both javascript and purescript darn install -D && darn install-ps # for docker setup
yarn install -D && yarn install-ps # for manual setup
``` ```
If something goes wrong building after a deps update, you may clean If something goes wrong building after a deps update, you may clean
build artifacts and try again: build artifacts and try again:
```shell ```shell
yarn clean-js # clean javascript, very useful # for docker setup
yarn clean-ps # clean purescript, should never be required, possible purescript bug darn clean-js # clean javascript, very useful
yarn clean # clean both purescript and javascript darn clean-ps # clean purescript, should never be required, possible purescript bug
darn clean # clean both purescript and javascript
# for manual setup
yarn clean-js
yarn clean-ps
yarn clean
``` ```
If you edit the SASS, you'll need to rebuild the CSS: If you edit the SASS, you'll need to rebuild the CSS:
```shell ```shell
yarn sass darn css # for docker setup
yarn css # for manual setup
``` ```
<!-- A `purs ide` connection will be available on port 9002 while the --> <!-- A `purs ide` connection will be available on port 9002 while the -->
<!-- development server is running. --> <!-- development server is running. -->
A guide to getting set up with the IDE integration is coming soon, I hope. A guide to getting set up with the IDE integration is coming soon, I hope.
of this document.
### Note to contributors ### Note to contributors
...@@ -139,20 +198,6 @@ Please follow CONTRIBUTING.md ...@@ -139,20 +198,6 @@ Please follow CONTRIBUTING.md
### How do I? ### How do I?
#### Change which backend to connect to?
Edit `Config.purs`. Find the function `endConfig'` just after the
imports and edit `back`. The definitions are not far below, just after
the definitions of the various `front` options.
Example (using `demo.gargantext.org` as backend):
```
endConfig' :: ApiVersion -> EndConfig
endConfig' v = { front : frontRelative
, back : backDemo v }
```
#### Add a javascript dependency? #### Add a javascript dependency?
Add it to `package.json`, under `dependencies` if it is needed at Add it to `package.json`, under `dependencies` if it is needed at
...@@ -173,13 +218,13 @@ works. It's written in dhall, so you can use comments and such. ...@@ -173,13 +218,13 @@ works. It's written in dhall, so you can use comments and such.
You will then need to rebuild the package set: You will then need to rebuild the package set:
```shell ```shell
yarn rebuild-set yarn rebuild-set # or darn rebuild-set
``` ```
#### Upgrade the base package set local is based on to latest? #### Upgrade the base package set local is based on to latest?
```shell ```shell
yarn rebase-set && yarn rebuild-set yarn rebase-set && yarn rebuild-set # or darn rebase-set && darn rebuild-set
``` ```
This will occasionally result in swearing when you go on to build. This will occasionally result in swearing when you go on to build.
......
...@@ -3,29 +3,16 @@ ...@@ -3,29 +3,16 @@
<head> <head>
<meta charset="utf-8"/> <meta charset="utf-8"/>
<title>CNRS GarganText</title> <title>CNRS GarganText</title>
<!-- <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet"> -->
<!--<link href="https://use.fontawesome.com/releases/v5.0.8/styles/all.css" rel="stylesheet">-->
<link rel="stylesheet" href="icons/forkawesome.css"> <link rel="stylesheet" href="icons/forkawesome.css">
<!--<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/fork-awesome@1.1.7/css/fork-awesome.min.css" integrity="sha256-gsmEoJAws/Kd3CjuOQzLie5Q3yshhvmo7YNtBG7aaEY=" crossorigin="anonymous">-->
<link href="styles/login.min.css" rel="stylesheet"> <link href="styles/login.min.css" rel="stylesheet">
<link href="styles/bootstrap.min.css" rel="stylesheet"> <link href="styles/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" type="text/css" href="styles/context-menu.css"/>
<link rel="stylesheet" type="text/css" href="styles/menu.css"/>
<link rel="stylesheet" type="text/css" href="styles/highlightjs-solarized-light.css"/> <link rel="stylesheet" type="text/css" href="styles/highlightjs-solarized-light.css"/>
<link href="styles/Graph.css" rel="stylesheet" type="text/css" /> <link href="styles/sass.css" rel="stylesheet" type="text/css" />
<link href="styles/Login.css" rel="stylesheet" type="text/css" /> <style> * {margin: 0; padding: 0; list-style: none;} </style>
<link href="styles/Tree.css" rel="stylesheet" type="text/css" />
<link href="styles/CodeEditor.css" rel="stylesheet" type="text/css" />
<link href="styles/Styles.css" rel="stylesheet" type="text/css" />
<link href="styles/range-slider.css" rel="stylesheet" type="text/css" />
<style>
* {margin: 0; padding: 0; list-style: none;}
</style>
</head> </head>
<body> <body>
<div id="app" class ="container-fluid"></div> <div id="app" class ="container-fluid"></div>
<div id="portal"></div> <div id="portal"></div>
<script src="bundle.js"></script> <script src="bundle.js"></script>
<script src="js/bootstrap-native.min.js"></script>
</body> </body>
</html> </html>
.code-editor-heading {
display: flex;
}
.code-editor-heading .renameable {
flex-grow: 2;
}
.code-editor-heading .renameable .text {
padding-right: 10px;
}
.code-editor-heading .buttons-right {
display: flex;
justify-content: flex-end;
}
.code-editor .toolbar {
display: flex;
justify-content: flex-start;
width: 100%;
}
.code-editor .editor {
display: flex;
width: 100%;
}
.code-editor .editor .code-area {
flex-grow: 1;
max-height: 200px;
min-width: 25%;
overflow: auto;
}
.code-editor .editor .code-area .code-container {
background-color: #fafafa;
box-sizing: border-box;
position: relative;
font-family: Fira code, Fira Mono, Consolas, Menlo, Courier, monospace;
font-size: 12px;
font-variant-ligatures: common-ligatures;
line-height: 1.5;
overflow: hidden;
padding: 0px;
text-align: left;
}
.code-editor .editor .code-area .code-container textarea {
border: 0px;
color: inherit;
position: absolute;
left: 0px;
top: 0px;
resize: none;
height: 100%;
overflow: hidden;
width: 100%;
-webkit-text-fill-color: transparent;
box-sizing: inherit;
display: inherit;
margin: 0px;
padding: 10px;
overflow-wrap: break-word;
white-space: pre-wrap;
word-break: keep-all;
font-family: inherit;
font-size: inherit;
font-style: inherit;
font-variant-ligatures: inherit;
font-weight: inherit;
letter-spacing: inherit;
line-height: inherit;
text-indent: inherit;
text-rendering: inherit;
text-transform: inherit;
}
.code-editor .editor .code-area .code-container pre {
background: rgba(0, 0, 0, 0) none repeat scroll 0% 0%;
border: 0px none;
color: #000;
pointer-events: none;
position: relative;
box-sizing: inherit;
display: inherit;
margin: 0px;
padding: 10px;
overflow-wrap: break-word;
white-space: pre-wrap;
word-break: keep-all;
font-family: inherit;
font-size: inherit;
font-style: inherit;
font-variant-ligatures: inherit;
font-weight: inherit;
letter-spacing: inherit;
line-height: inherit;
text-indent: inherit;
text-rendering: inherit;
text-transform: inherit;
}
.code-editor .editor .v-divider {
border-left: 1px solid gray;
cursor: sw-resize;
height: 100%;
margin-left: 5px;
margin-right: 5px;
width: 1px;
}
.code-editor .editor .html {
flex-grow: 2;
margin-left: 25px;
padding-left: 25px;
}
.code-editor .editor .html.language-haskell {
font-family: Fira code, Fira Mono, Consolas, Menlo, Courier, monospace;
white-space: pre;
}
.code-editor .editor .html.language-python {
font-family: Fira code, Fira Mono, Consolas, Menlo, Courier, monospace;
white-space: pre;
}
.code-editor .editor .html.language-json {
font-family: Fira code, Fira Mono, Consolas, Menlo, Courier, monospace;
white-space: pre;
}
.code-editor .editor .html.language-md ul li {
list-style: disc !important;
}
.code-editor .editor .html.language-md ol li {
list-style: decimal !important;
}
/*# sourceMappingURL=CodeEditor.css.map */
#graph-explorer #toolbar {
display: flex;
flex-direction: column;
}
#graph-explorer #toolbar ul {
display: flex;
flex-direction: row;
margin: 0;
}
#graph-explorer #toolbar ul li {
display: flex;
max-width: 200px;
}
#graph-explorer #toggle-container {
position: fixed;
z-index: 999;
right: 25%;
top: 10px;
width: 50%;
}
#graph-explorer #toggle-container .container-fluid {
padding-top: 90px;
}
#graph-explorer #controls-container {
position: fixed;
z-index: 999;
backdrop-filter: blur(4px);
background: rgba(255, 255, 255, 0.75);
overflow: auto;
left: 0;
right: 0;
top: 60px;
}
#graph-explorer .graph-tree {
position: absolute;
max-height: 600px;
top: 170px;
background-color: #fff;
z-index: 1;
}
#graph-explorer .lefthanded .graph-tree {
left: 80%;
}
#graph-explorer .righthanded .graph-tree {
left: 0%;
}
#graph-explorer #graph-view {
height: 95%;
}
#graph-explorer #sp-container {
position: absolute;
max-height: 600px;
top: 170px;
border: 1px white solid;
background-color: white;
width: 28%;
z-index: 15;
}
#graph-explorer #sp-container #myTab {
marginBottom: 18px;
marginTop: 18px;
}
#graph-explorer #sp-container #myTabContent {
borderBottom: 1px solid black;
paddingBottom: 19px;
}
#graph-explorer #sp-container #horizontal-checkbox ul {
display: inline;
float: left;
}
#graph-explorer .lefthanded #sp-container {
left: 0%;
}
#graph-explorer .righthanded #sp-container {
left: 70%;
}
#graph-explorer #tree {
position: absolute;
z-index: 1;
}
.input-with-autocomplete .completions {
position: fixed;
max-height: 300px;
overflow-y: scroll;
width: 300px;
top: 100px;
}
/*# sourceMappingURL=Graph.css.map */
#dafixedtop {
z-index: 999;
}
.logoSmall {
line-height: 15px;
height: 10px;
padding: 10px 10px;
}
#logo-designed {
border: 15px;
}
#logo-designed img {
height: 150px;
border: 3px solid white;
}
#page-wrapper {
margin-top: 96px;
}
#user-page-header {
border-bottom: 1px solid black;
}
#user-page-info {
margin-top: 38px;
}
.tableHeader {
color: white;
}
#toolbar {
display: inline;
}
#toolbar ul li {
display: inline;
margin-right: 19px;
}
#toolbar ul li form {
display: inline;
}
#horizontal-checkbox ul li {
display: inline;
float: left;
margin-top: 12px;
margin-right: 21px;
}
li#rename #rename-a {
display: none;
position: absolute;
left: 125px;
}
#node-popup-tooltip {
background-color: white;
border-bottom-left-radius: 6px;
border-bottom-right-radius: 6px;
border-top-left-radius: 6px;
border-top-right-radius: 6px;
}
#node-popup-tooltip:hover {
border: none;
text-decoration: none;
}
#node-popup-tooltip .popup-container {
display: flex;
flex-direction: colum;
}
#node-popup-tooltip .popup-container .panel {
border: 1px solid rgba(0, 0, 0, 0.2);
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
margin-bottom: 0px;
}
#node-popup-tooltip .popup-container .panel .glyphicon-pencil {
color: black;
}
#node-popup-tooltip .popup-container .panel .panel-body {
display: flex;
justify-content: center;
background-color: white;
border: none;
}
#node-popup-tooltip .popup-container .panel .panel-body .spacer {
margin: 10px;
}
#node-popup-tooltip .popup-container .frame-search.panel {
border: 1px solid rgba(0, 0, 0, 0.2);
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
height: 600px;
width: 1300px;
}
#create-node-tooltip {
position: absolute;
left: 96px;
top: -64px;
background-color: white;
z-index: 1000;
}
#create-node-tooltip .panel-body input {
min-width: 200px;
}
#file-type-tooltip {
position: absolute;
left: 96px;
top: -64px;
background-color: white;
z-index: 1000;
}
#file-type-tooltip .panel-body select {
min-width: 200px;
}
.glyphitem {
top: 0;
display: inline-block;
float: right;
opacity: 0.6;
padding-right: 5px;
cursor: pointer;
transition: transform 0.1s ease-out 0s;
font-size: 15px;
text-align: center;
}
.glyphitem:hover {
display: inline-block;
opacity: 1;
transform: scale(1.4);
}
#sp-container {
-webkit-transition: width 2s;
transition: width 2s;
}
.nooverflow {
max-width: 300px;
height: 24px;
overflow: hidden;
text-overflow: ellipsis;
}
.nooverflow:hover {
overflow: visible;
height: auto;
}
#graph-tree .tree {
margin-top: 27px;
}
.nopadding {
padding: 0 !important;
margin: 0 !important;
}
.row-no-padding > [class*=col-] {
padding-left: 0 !important;
padding-right: 0 !important;
}
.tab-pane .reload-btn {
padding-right: 6px;
}
.flex {
display: flex;
}
.flex-end {
display: flex;
justify-content: flex-end;
}
.flex-center {
display: flex;
flew-wrap: wrap;
justify-content: center;
}
.flex-space-between, .flex-center {
display: flex;
justify-content: space-between;
}
a:focus, a:hover {
cursor: pointer;
}
/*# sourceMappingURL=Login.css.map */
#page-wrapper .cache-toggle {
cursor: pointer;
}
.simple-layout {
height: 100%;
}
.simple-layout .spinner {
position: absolute;
left: 50%;
top: 50%;
}
/*# sourceMappingURL=Styles.css.map */
#page-wrapper
.cache-toggle
cursor: pointer
.simple-layout
height: 100%
.spinner
position: absolute
left: 50%
top: 50%
body > .tree ul > li:first-child::before {
top: 12px;
}
li .leaf {
display: flex;
flex-direction: row;
}
li .leaf .folder-icon {
padding: 0 2 0 2;
}
li .leaf a.settings {
cursor: pointer;
display: block;
padding: 0 2 0 2;
text-decoration: none;
visibility: hidden;
z-index: 1;
}
li .leaf:hover a.settings {
visibility: visible;
}
.tree {
margin-top: 20px;
}
.tree ul li {
position: relative;
}
.tree ul li::after {
content: " ";
height: 1px;
position: absolute;
top: 12px;
}
.tree ul li::before {
bottom: -12px;
content: " ";
height: 7px;
position: absolute;
top: 5px;
}
.tree ul li:not(:first-child):last-child::before {
display: none;
}
.tree ul li:only-child::before {
bottom: 7px;
content: " ";
display: list-item;
position: absolute;
width: 1px;
top: 5px;
}
.tree ul li.with-children::after {
background-color: #000;
}
.tree ul li.with-children::before {
background-color: #000;
}
.tree .lefthanded .leaf {
justify-content: flex-end;
}
.tree .lefthanded ul {
margin-right: 5px;
}
.tree .lefthanded ul li {
margin-right: 10px;
padding-right: 5px;
}
.tree .lefthanded ul li.with-children::after {
right: -10px;
width: 5px;
}
.tree .lefthanded ul li.with-children::before {
right: -10px;
width: 1px;
}
.tree .righthanded .leaf {
justify-content: flex-start;
}
.tree .righthanded ul {
margin-left: 5px;
}
.tree .righthanded ul li {
margin-left: 10px;
padding-left: 5px;
}
.tree .righthanded ul li.with-children::after {
left: -10px;
width: 5px;
}
.tree .righthanded ul li.with-children::before {
left: -10px;
width: 1px;
}
.tree .righthanded ul li.with-children:only::before {
background-color: #000;
right: 10px;
}
.tree .file-dropped {
background-color: #d8dfe5;
}
.tree .node-actions {
padding-left: 5px;
}
.tree .node-actions .update-button.enabled {
cursor: pointer;
}
.tree .node-actions .update-button.disabled {
cursor: wait;
}
.tree .node {
margin-top: 1px;
}
.tree .node.node-type-valid .text {
color: blue;
text-decoration: underline;
}
.progress-pie {
background: rgba(51, 122, 183, 0.1);
border-radius: 100%;
height: calc(var(--size, 14) * 1px);
overflow: hidden;
position: relative;
width: calc(var(--size, 14) * 1px);
}
.progress-pie .progress-pie-segment {
--a: calc(var(--over50, 0) * -100%);
--b: calc((1 + var(--over50, 0)) * 100%);
--degrees: calc((var(--offset, 0) / 100) * 360);
-webkit-clip-path: polygon(var(--a) var(--a), var(--b) var(--a), var(--b) var(--b), var(--a) var(--b));
clip-path: polygon(var(--a) var(--a), var(--b) var(--a), var(--b) var(--b), var(--a) var(--b));
height: 100%;
position: absolute;
transform: translate(0, -50%) rotate(90deg) rotate(calc(var(--degrees) * 1deg));
transform-origin: 50% 100%;
width: 100%;
z-index: calc(1 + var(--over50));
}
.progress-pie .progress-pie-segment:after, .progress-pie .progress-pie-segment:before {
background: var(--bg, #337ab7);
content: "";
height: 100%;
position: absolute;
width: 100%;
}
.progress-pie .progress-pie-segment:before {
--degrees: calc((var(--value, 45) / 100) * 360);
transform: translate(0, 100%) rotate(calc(var(--degrees) * 1deg));
transform-origin: 50% 0%;
}
.progress-pie .progress-pie-segment:after {
opacity: var(--over50, 0);
}
#node-popup-tooltip .tree .node {
margin-top: 5px;
}
#node-popup-tooltip .tree .children .node {
padding-left: 15px;
}
/*# sourceMappingURL=Tree.css.map */
.context-menu {
position : absolute;
left : 96px;
top:-64px;
background-color: white;
z-index: 1000;
}
.context-menu a.list-group-item {
cursor: pointer;
}
.search-bar-container {
margin-top: 11px;
text-align: center;
max-width: 800px;
height: 33px;
float: left;
display: grid;
grid-template-columns: auto auto auto;
}
.search-bar-toggle {
padding: 2px;
margin: 2px;
border: 0;
}
.search-bar.closed {
display: none;
}
/* styles for menu.html template (navbar etc) */
#dafixedtop .navbar-text, #graphsfixedtop .navbar-text {
margin: 0 ;
padding-top: 15px;
padding-bottom: 15px;
float: none;
}
#corporatop.nav-tabs > li {
padding-left:1;
padding-right:1;
}
#corporatop.nav-tabs > li > a {
padding-top: 8;
padding-bottom: 8;
line-height: .85;
margin-bottom: -5px;
}
.spacing-class { margin-right : 10px;}
.exportbtn {
/* border: 1px solid #333 ; */
margin-top:17px ; /* valigns with bootstrap h2 */
}
.btn .glyphicon {
/* glyphicons are always rendered too high within bootstrap buttons */
vertical-align:middle
}
/* graph name => editable input => submitName() => minimsg */
.editable {
color: grey ;
}
#graphname-edit {
color: white;
background-color: transparent;
border: none;
max-width: 8em;
}
.minimsg {
font-size: .7em ;
padding: 7p0x 9px;
}
.minimsg * {
line-height: 100%;
}
{"version":3,"sourceRoot":"","sources":["../../src/sass/range-slider.sass"],"names":[],"mappings":"AAAA;EACE;AACA;EACA;;AAEA;EACE;;AAEA;EACE;EACA;EACA;EACA;EACA;;AAEF;EACE;EACA;EACA;EACA;;AAEF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EAEA;EAEA;EAEA;;AAEA;EACE;EAEA;EACA;EACA","file":"range-slider.css"}
\ No newline at end of file
This diff is collapsed.
{"version":3,"sourceRoot":"","sources":["../../src/sass/_menu.sass","../../src/sass/_context_menu.sass","../../src/sass/_graph.sass","../../src/sass/_login.sass","../../src/sass/_tree.sass","../../src/sass/_code_editor.sass","../../src/sass/_styles.sass","../../src/sass/_range_slider.sass"],"names":[],"mappings":"AAAA;AAEA;EACI;EACA;EACA;EACA;;;AAEJ;EACI;EACA;;;AAEJ;EACI;EACA;EACA;EACA;;;AAEJ;EACE;;;AAEF;AACI;EACA;;;AAEJ;AACI;EACA;;;AAGJ;AACA;EACI;;;AAEJ;EACI;EACA;EACA;EACA;;;AAEJ;EACE;EACA;;;AAEF;EACE;;;AC7CF;EACE;EACA;EACA;EACA;EACA;;;AAEF;EACE;;;AAEF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;;AAEF;EACE;EACA;EACA;;;AAEF;EACE;;;ACjBA;EACE;EACA;;AAEA;EACE;EACA;EACA;;AACA;EACE;EACA;;AAEN;EACE;EACA;EACA;EACA;EACA;;AACA;EACE;;AAEJ;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEF;EAtCA;EACA;EAEA;EAqCE;EACA;;AACF;EACE;;AACF;EACE;;AAEF;EACE;;AAEF;EAlDA;EACA;EAEA;EAiDE;EACA;EACA;EACA;;AAEA;EACE;EACA;;AAEF;EACE;EACA;;AAGA;EACE;EACA;;AACN;EACE;;AACF;EACE;;AAEF;EACE;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;;;ACrFJ;EACE;;;AAEF;EACE;EACA;EACA;;;AAEF;EACE;;AACA;EACE;EACA;;;AAEJ;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAGF;EACE;;AAEE;EACE;EACA;;AACA;EACE;;;AAIJ;EACE;EACA;EACA;EACA;;;AAKJ;EACE;EACA;EACA;;;AAGJ;EACE;EACA;EACA;EACA;EACA;;AACA;EACE;EACA;;AACF;EACE;EACA;;AACA;EACE;EACA;EACA;;AACA;EACE;;AACF;EACE;EACA;EACA;EACA;;AACA;EACE;;AACN;EACE;EACA;EACA;EACA;;;AAGN;EACE;EACA;EACA;EACA;EACA;;AAGE;EACE;;;AAEN;EACE;EACA;EACA;EACA;EACA;;AAGE;EACE;;;AAEN;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;EACA;EACA;;;AAEJ;EACE;EACA;;;AAGF;EACE;EACA;EACA;EACA;;AACA;EACE;EACA;;;AAGF;EACE;;;AAEJ;EACI;EACA;;;AAEJ;EACI;EACA;;;AAGF;EACE;;;AAEJ;EACE;;;AAEF;EACE;EACA;;;AAEF;EACE;EACA;EACA;;;AAEF;EACE;EACA;;;AAEF;EACE;;;AC1KF;EACE;;;AAGA;EACE;EACA;;AACA;EACE;;AACF;EACE;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;;;AAER;EACE;;AAEE;EACE;;AACA;EACE;EACA;EACA;EACA;;AACF;EACE;EACA;EACA;EACA;EACA;;AACF;EACE;;AACF;EACE;EACA;EACA;EAEA;EACA;EACA;;AAEA;EACE;;AACF;EACE;;AAGN;EACE;;AACF;EACE;;AACA;EACE;EACA;;AAEE;EACE;EACA;;AACF;EACE;EACA;;AAIR;EACE;;AACF;EACE;;AACA;EACE;EACA;;AAEE;EACE;EACA;;AACF;EACE;EACA;;AACF;EACE;EACA;;AAEV;EACE;;AACF;EACE;;AAEE;EACE;;AACF;EACE;;AACN;EACE;;AAEE;EACE;EACA;;;AAGR;EACE;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EAEE;EACA;EACA;EACA;EACA;;AAEF;EACE;EACA;EACA;;AAEF;EACE;;;AAIF;EACE;;AAEA;EACE;;;AC/HR;EACE;;AAEA;EACE;;AACA;EACE;;AACJ;EACE;EACA;;;AAGF;EACE;EACA;EACA;;AACF;EACE;EACA;;AACA;EACE;EACA;EACA;EACA;;AACA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AACA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EArDR;EACA;EACA;EACA;EACA;EACA;EACA;EAlBA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AA2DM;EACE;EACA;EACA;EACA;EACA;EA7DR;EACA;EACA;EACA;EACA;EACA;EACA;EAlBA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAmEE;EACE;EACA;EACA;EACA;EACA;EACA;;AACF;EACE;EACA;EACA;;AACA;EACE;EACA;;AACF;EACE;EACA;;AACF;EACE;EACA;;AAGE;EACE;;AAEF;EACE;;;ACtGV;EACE;;AACF;EACE;EACA;EACA;EACA;EACA;EACA;;AACA;EACE;;AAGE;EACE;EACA;;AAEF;EACE;EACA;;;AAEV;EACE;;AACA;EACE;EACA;EACA;;;AAKE;EACE;EACA;;AACF;EACE;;AACA;EACE;EACA;;AACJ;EACE;;AACA;EACE;;AACJ;EACE;;;AAER;EACE;;;AChDF;EACE;AACA;EACA;;AAEA;EACE;;AAEA;EACE;EACA;EACA;EACA;EACA;;AAEF;EACE;EACA;EACA;EACA;;AAEF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EAEA;EAEA;EAEA;;AAEA;EACE;EAEA;EACA;EACA","file":"sass.css"}
\ No newline at end of file
version: "3.5"
services:
frontend:
build:
context: .
dockerfile: "Dockerfile.dev"
stdin_open: true
tty: true
user: $UID:$GID
ports:
- 5000:5000
volumes:
- .:/opt/app
- /etc/group:/etc/group:ro
- /etc/passwd:/etc/passwd:ro
- /etc/shadow:/etc/shadow:ro
\ No newline at end of file
export UID=$(id -u)
export GID=$(id -g)
alias darn="docker-compose run frontend yarn"
<!doctype>
<html>
<head>
<meta charset="utf-8"/>
<title>CNRS GarganText</title>
<link rel="stylesheet" href="dist/icons/forkawesome.css">
<link href="dist/styles/login.min.css" rel="stylesheet">
<link href="dist/styles/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" type="text/css" href="dist/styles/highlightjs-solarized-light.css"/>
<link href="dist/styles/sass.css" rel="stylesheet" type="text/css" />
<style> * {margin: 0; padding: 0; list-style: none;} </style>
</head>
<body>
<div id="app" class ="container-fluid"></div>
<div id="portal"></div>
<script src="app.js"></script>
</body>
</html>
{ {
"name": "Gargantext", "name": "Gargantext",
"version": "0.0.1.91.7", "version": "0.0.2.2.1",
"scripts": { "scripts": {
"rebase-set": "spago package-set-upgrade && spago psc-package-insdhall", "rebase-set": "spago package-set-upgrade && spago psc-package-insdhall",
"rebuild-set": "spago psc-package-insdhall", "rebuild-set": "spago psc-package-insdhall",
"install-ps": "psc-package install", "install-ps": "psc-package install",
"compile": "pulp --psc-package build", "compile": "pulp build",
"build": "pulp --psc-package browserify --no-check-main -t dist/bundle.js", "build": "pulp browserify -t dist/bundle.js",
"sass": "sass dist/styles/", "css": "sass src/sass/sass.sass:dist/styles/sass.css",
"docs": "pulp docs -- --format html", "docs": "pulp docs -- --format html",
"repl": "pulp --psc-package repl", "repl": "pulp repl",
"clean": "rm -Rf output node_modules", "clean": "rm -Rf output node_modules",
"clean-js": "rm -Rf node_modules", "clean-js": "rm -Rf node_modules",
"clean-ps": "rm -Rf output", "clean-ps": "rm -Rf output",
"test": "pulp test --no-check-main", "test": "pulp test",
"server": "serve dist" "server": "serve dist",
"prod": "yarn prod:compile && yarn prod:dce && yarn prod:bundle && yarn prod:pack",
"prod:compile": "pulp build -- -g corefn",
"prod:dce": "zephyr -f Main.main",
"prod:bundle": "pulp browserify --skip-compile -o dce-output -t app.js",
"prod:pack": "parcel build index.html -d prod --public-url . --no-source-maps"
}, },
"dependencies": { "dependencies": {
"aes-js": "^3.1.1", "aes-js": "^3.1.1",
...@@ -32,8 +37,11 @@ ...@@ -32,8 +37,11 @@
"sigma": "git://github.com/poorscript/sigma.js#garg" "sigma": "git://github.com/poorscript/sigma.js#garg"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.12.9",
"@babel/preset-react": "^7.12.7",
"parcel": "^1.12.4",
"psc-package": "^4.0.1", "psc-package": "^4.0.1",
"pulp": "^14.0.0", "pulp": "^15.0.0",
"purescript": "^0.13.8", "purescript": "^0.13.8",
"purescript-language-server": "^0.12.9", "purescript-language-server": "^0.12.9",
"react-testing-library": "^6.1.2", "react-testing-library": "^6.1.2",
......
../dist/images
\ No newline at end of file
15747
\ No newline at end of file
...@@ -5,9 +5,11 @@ import Data.Argonaut.Parser (jsonParser) ...@@ -5,9 +5,11 @@ import Data.Argonaut.Parser (jsonParser)
import Data.Array as A import Data.Array as A
import Data.Either (Either(..)) import Data.Either (Either(..))
import Data.Map as Map import Data.Map as Map
import Data.Maybe (Maybe(..)) import Data.Maybe (Maybe(..), maybe, fromMaybe)
import Data.Tuple (snd)
import DOM.Simple.Console (log2) import DOM.Simple.Console (log2)
import Effect (Effect) import Effect (Effect)
import Reactix as R
import Web.Storage.Storage as WSS import Web.Storage.Storage as WSS
import Gargantext.Prelude import Gargantext.Prelude
...@@ -19,7 +21,8 @@ import Gargantext.Utils.Reactix as R2 ...@@ -19,7 +21,8 @@ import Gargantext.Utils.Reactix as R2
localStorageKey :: String localStorageKey :: String
localStorageKey = "garg-async-tasks" localStorageKey = "garg-async-tasks"
type Storage = Map.Map Int (Array GT.AsyncTaskWithType)
type Storage = Map.Map GT.NodeID (Array GT.AsyncTaskWithType)
empty :: Storage empty :: Storage
empty = Map.empty empty = Map.empty
...@@ -37,6 +40,45 @@ getAsyncTasks = R2.getls >>= WSS.getItem localStorageKey >>= handleMaybe ...@@ -37,6 +40,45 @@ getAsyncTasks = R2.getls >>= WSS.getItem localStorageKey >>= handleMaybe
parse s = GU.mapLeft (log2 "Error parsing serialised sessions:") (jsonParser s) parse s = GU.mapLeft (log2 "Error parsing serialised sessions:") (jsonParser s)
decode j = GU.mapLeft (log2 "Error decoding serialised sessions:") (decodeJson j) decode j = GU.mapLeft (log2 "Error decoding serialised sessions:") (decodeJson j)
getTasks :: Record ReductorProps -> GT.NodeID -> Array GT.AsyncTaskWithType
getTasks { storage } nodeId = fromMaybe [] $ Map.lookup nodeId storage
removeTaskFromList :: Array GT.AsyncTaskWithType -> GT.AsyncTaskWithType -> Array GT.AsyncTaskWithType removeTaskFromList :: Array GT.AsyncTaskWithType -> GT.AsyncTaskWithType -> Array GT.AsyncTaskWithType
removeTaskFromList ts (GT.AsyncTaskWithType { task: GT.AsyncTask { id: id' } }) = removeTaskFromList ts (GT.AsyncTaskWithType { task: GT.AsyncTask { id: id' } }) =
A.filter (\(GT.AsyncTaskWithType { task: GT.AsyncTask { id: id'' } }) -> id' /= id'') ts A.filter (\(GT.AsyncTaskWithType { task: GT.AsyncTask { id: id'' } }) -> id' /= id'') ts
type ReductorProps = (
appReload :: GT.ReloadS
, treeReload :: GT.ReloadS
, storage :: Storage
)
type Reductor = R2.Reductor (Record ReductorProps) Action
type ReductorAction = Action -> Effect Unit
type OnFinish = Effect Unit
useTasks :: GT.ReloadS -> GT.ReloadS -> R.Hooks Reductor
useTasks appReload treeReload = R2.useReductor act initializer unit
where
act :: R2.Actor (Record ReductorProps) Action
act a s = action s a
initializer _ = do
storage <- getAsyncTasks
pure { appReload, treeReload, storage }
data Action =
Insert GT.NodeID GT.AsyncTaskWithType
| Finish GT.NodeID GT.AsyncTaskWithType
| Remove GT.NodeID GT.AsyncTaskWithType
action :: Record ReductorProps -> Action -> Effect (Record ReductorProps)
action p@{ treeReload, storage } (Insert nodeId t) = do
_ <- snd treeReload $ (_ + 1)
let newStorage = Map.alter (maybe (Just [t]) (\ts -> Just $ A.cons t ts)) nodeId storage
pure $ p { storage = newStorage }
action p (Finish nodeId t) = do
action p (Remove nodeId t)
action p@{ appReload, storage } (Remove nodeId t) = do
_ <- snd appReload $ (_ + 1)
let newStorage = Map.alter (maybe Nothing $ (\ts -> Just $ removeTaskFromList ts t)) nodeId storage
pure $ p { storage = newStorage }
...@@ -11,22 +11,23 @@ ...@@ -11,22 +11,23 @@
-- | 2. We will need a more ambitious search algorithm for skipgrams. -- | 2. We will need a more ambitious search algorithm for skipgrams.
module Gargantext.Components.Annotation.AnnotatedField where module Gargantext.Components.Annotation.AnnotatedField where
import Prelude
import Data.List ( List(..), (:) ) import Data.List ( List(..), (:) )
import Data.Maybe ( Maybe(..), maybe ) import Data.Maybe ( Maybe(..), maybe )
import Data.Tuple ( Tuple(..) ) import Data.Tuple (Tuple(..))
import Data.Tuple.Nested ( (/\) ) import Data.Tuple.Nested ( (/\) )
import DOM.Simple.Console (log2) --import DOM.Simple.Console (log2)
import DOM.Simple.Event as DE import DOM.Simple.Event as DE
import Effect ( Effect ) import Effect ( Effect )
import Reactix as R import Reactix as R
import Reactix.DOM.HTML as HTML import Reactix.DOM.HTML as HTML
import Reactix.SyntheticEvent as E import Reactix.SyntheticEvent as E
import Gargantext.Prelude
import Gargantext.Types (CTabNgramType(..), TermList) import Gargantext.Types (CTabNgramType(..), TermList)
import Gargantext.Components.Annotation.Utils ( termBootstrapClass ) import Gargantext.Components.Annotation.Utils ( termBootstrapClass )
import Gargantext.Components.NgramsTable.Core (NgramsTable, NgramsTerm, findNgramTermList, highlightNgrams, normNgram) import Gargantext.Components.NgramsTable.Core (NgramsTable, NgramsTerm, findNgramTermList, highlightNgrams, normNgram)
import Gargantext.Components.Annotation.Menu ( AnnotationMenu, annotationMenu, MenuType(..) ) import Gargantext.Components.Annotation.Menu ( annotationMenu, MenuType(..) )
import Gargantext.Utils.Selection as Sel import Gargantext.Utils.Selection as Sel
thisModule :: String thisModule :: String
...@@ -49,107 +50,63 @@ annotatedField p = R.createElement annotatedFieldComponent p [] ...@@ -49,107 +50,63 @@ annotatedField p = R.createElement annotatedFieldComponent p []
annotatedFieldComponent :: R.Component Props annotatedFieldComponent :: R.Component Props
annotatedFieldComponent = R.hooksComponentWithModule thisModule "annotatedField" cpt annotatedFieldComponent = R.hooksComponentWithModule thisModule "annotatedField" cpt
where where
cpt {ngrams,setTermList,text} _ = do cpt {ngrams,setTermList,text: fieldText} _ = do
mMenu@(_ /\ setMenu) <- R.useState' Nothing (_ /\ setRedrawMenu) <- R.useState' false
menuRef <- R.useRef Nothing menuRef <- R.useRef Nothing
let wrapperProps = { className: "annotated-field-wrapper" } let wrapperProps = { className: "annotated-field-wrapper" }
onSelect :: Maybe (Tuple NgramsTerm TermList) -> MouseEvent -> Effect Unit redrawMenu = setRedrawMenu not
onSelect Nothing event = do
maybeShowMenu setMenu menuRef setTermList ngrams event hideMenu = do
onSelect (Just (Tuple ngram list)) event = do R.setRef menuRef Nothing
redrawMenu
showMenu { event, getList, menuType, ngram } = do
let x = E.clientX event let x = E.clientX event
y = E.clientY event y = E.clientY event
-- n = normNgram CTabTerms text
list = getList ngram
setList t = do setList t = do
R.setRef menuRef Nothing setTermList ngram list t
setTermList ngram (Just list) t hideMenu
--setMenu (const Nothing) E.preventDefault event
menu = Just { --range <- Sel.getRange sel 0
x --log2 "[showMenu] selection range" $ Sel.rangeToTuple range
let menu = Just
{ x
, y , y
, list: Just list , list
, menuType: SetTermListItem , menuType
, onClose: \_ -> R.setRef menuRef Nothing , onClose: hideMenu
, setList , setList
} }
R.setRef menuRef menu R.setRef menuRef menu
setMenu $ const menu redrawMenu
mapCompile (Tuple t l) = {text: t, list: l, onSelect}
compiled = map mapCompile $ compile ngrams text
runs =
HTML.div { className: "annotated-field-runs" } $ map annotateRun compiled
--pure $ HTML.div wrapperProps [maybeAddMenu mMenu runs]
pure $ HTML.div wrapperProps [ addMenu { menuRef }, runs ]
type AddMenuProps = (
menuRef :: R.Ref (Maybe AnnotationMenu)
)
addMenu :: Record AddMenuProps -> R.Element
addMenu p = R.createElement addMenuCpt p []
addMenuCpt :: R.Component AddMenuProps
addMenuCpt = R.hooksComponentWithModule thisModule "addMenu" cpt
where
cpt { menuRef } _ = do
(mMenu /\ setmMenu) <- R.useState' (Nothing :: Maybe AnnotationMenu)
R.useEffect' $ do onSelect :: Maybe (Tuple NgramsTerm TermList) -> MouseEvent -> Effect Unit
let m = R.readRef menuRef onSelect (Just (Tuple ngram list)) event =
--log2 "[addMenu] menuRef" m showMenu { event, getList: const (Just list), menuType: SetTermListItem, ngram }
--log2 "[addMenu] mMenu" mMenu onSelect Nothing event = do
setmMenu $ const m
pure $ case mMenu of
Nothing -> HTML.div {} []
Just menu -> annotationMenu setmMenu menu
-- forall e. IsMouseEvent e => R.Setter (Maybe AnnotationMenu) -> R.Setter ? -> ? -> e -> Effect Unit
maybeShowMenu setMenu menuRef setTermList ngrams event = do
s <- Sel.getSelection s <- Sel.getSelection
--log2 "[maybeShowMenu] s" s
case s of case s of
Just sel -> do Just sel -> do
case Sel.selectionToString sel of case Sel.selectionToString sel of
"" -> pure unit "" -> hideMenu
sel' -> do sel' -> do
let x = E.clientX event showMenu { event, getList: findNgramTermList ngrams, menuType: NewNgram, ngram: normNgram CTabTerms sel' }
y = E.clientY event Nothing -> hideMenu
n = normNgram CTabTerms sel'
list = findNgramTermList ngrams n wrap (text /\ list) = {text, list, onSelect}
setList t = do
setTermList n list t pure $ HTML.div wrapperProps
R.setRef menuRef Nothing [ maybe (HTML.div {} []) annotationMenu $ R.readRef menuRef
--setMenu (const Nothing) , HTML.div { className: "annotated-field-runs" }
E.preventDefault event $ annotateRun
range <- Sel.getRange sel 0 <$> wrap
--log2 "[maybeShowMenu] selection range" $ Sel.rangeToTuple range <$> compile ngrams fieldText
let menu = Just { ]
x
, y
, list
, menuType: NewNgram
, onClose: \_ -> R.setRef menuRef Nothing
, setList
}
R.setRef menuRef menu
setMenu $ const $ menu
Nothing -> pure unit
-- Nothing -> do
-- R.setRef menuRef Nothing
maybeAddMenu
:: R.State (Maybe AnnotationMenu)
-> R.Element
-> R.Element
maybeAddMenu (Just props /\ setMenu) e = annotationMenu setMenu props <> e
maybeAddMenu _ e = e
compile :: NgramsTable -> Maybe String -> Array (Tuple String (List (Tuple NgramsTerm TermList))) compile :: NgramsTable -> Maybe String -> Array (Tuple String (List (Tuple NgramsTerm TermList)))
compile ngrams = maybe [] (highlightNgrams CTabTerms ngrams) compile ngrams = maybe [] (highlightNgrams CTabTerms ngrams)
...@@ -178,4 +135,3 @@ annotatedRunComponent = R.staticComponent "AnnotatedRun" cpt ...@@ -178,4 +135,3 @@ annotatedRunComponent = R.staticComponent "AnnotatedRun" cpt
where where
className = "annotation-run bg-" <> termBootstrapClass list className = "annotation-run bg-" <> termBootstrapClass list
...@@ -30,16 +30,16 @@ type Props = ...@@ -30,16 +30,16 @@ type Props =
type AnnotationMenu = { type AnnotationMenu = {
x :: Number x :: Number
, y :: Number , y :: Number
, onClose :: Unit -> Effect Unit , onClose :: Effect Unit
| Props | Props
} }
-- | An Annotation Menu is parameterised by a Maybe Termlist of the -- | An Annotation Menu is parameterised by a Maybe Termlist of the
-- | TermList the currently selected text belongs to -- | TermList the currently selected text belongs to
annotationMenu :: R.Setter (Maybe AnnotationMenu) -> AnnotationMenu -> R.Element annotationMenu :: AnnotationMenu -> R.Element
annotationMenu setMenu { x,y,list,menuType, onClose,setList } = annotationMenu {x, y, list, menuType, onClose, setList} =
CM.contextMenu { x,y, onClose, setMenu } [ CM.contextMenu {x, y, onClose} [
R.createElement annotationMenuCpt {list,menuType,setList} [] R.createElement annotationMenuCpt {list, menuType, setList} []
] ]
annotationMenuCpt :: R.Component Props annotationMenuCpt :: R.Component Props
......
This diff is collapsed.
...@@ -25,72 +25,53 @@ import Effect.Aff (Aff, launchAff) ...@@ -25,72 +25,53 @@ import Effect.Aff (Aff, launchAff)
import Effect.Class (liftEffect) import Effect.Class (liftEffect)
import Reactix as R import Reactix as R
import Reactix.DOM.HTML as H import Reactix.DOM.HTML as H
------------------------------------------------------------------------
import Gargantext.Prelude import Gargantext.Prelude
import Gargantext.Components.Category.Types
import Gargantext.Components.DocsTable.Types (DocumentsView(..), LocalCategories)
import Gargantext.Ends (Frontends, url) import Gargantext.Ends (Frontends, url)
import Gargantext.Hooks.Loader (useLoaderWithCacheAPI, HashedResponse(..)) import Gargantext.Hooks.Loader (useLoaderWithCacheAPI, HashedResponse(..))
import Gargantext.Utils.Reactix as R2 import Gargantext.Utils.Reactix as R2
import Gargantext.Routes as Routes import Gargantext.Routes as Routes
import Gargantext.Routes (SessionRoute(NodeAPI)) import Gargantext.Routes (SessionRoute(NodeAPI))
import Gargantext.Sessions (Session, sessionId, get, delete, put) import Gargantext.Sessions (Session, sessionId, get, delete, put)
import Gargantext.Types (NodeType(..), OrderBy(..), TableResult, TabType, showTabType') import Gargantext.Types (NodeID, NodeType(..), OrderBy(..), TableResult, TabType, showTabType')
import Gargantext.Utils.CacheAPI as GUC import Gargantext.Utils.CacheAPI as GUC
thisModule :: String
thisModule = "Gargantext.Components.Category"
------------------------------------------------------------------------ ------------------------------------------------------------------------
data Category = Trash | UnRead | Checked | Topic | Favorite
type CarousselProps = (
categories :: Array Category category :: Category
categories = [Trash, UnRead, Checked, Topic, Favorite] , nodeId :: NodeID
, row :: DocumentsView
derive instance genericFavorite :: Generic Category _ , session :: Session
instance showCategory :: Show Category where , setLocalCategories :: R.Setter LocalCategories
show = genericShow )
instance eqCategory :: Eq Category where
eq = genericEq
instance decodeJsonCategory :: DecodeJson Category where
decodeJson json = do
obj <- decodeJson json
pure $ decodeCategory obj
instance encodeJsonCategory :: EncodeJson Category where
encodeJson cat = encodeJson (cat2score cat)
favCategory :: Category -> Category
favCategory Favorite = Topic
favCategory _ = Favorite
trashCategory :: Category -> Category
trashCategory _ = Trash
-- TODO: ?
--trashCategory Trash = UnRead
decodeCategory :: Int -> Category
decodeCategory 0 = Trash
decodeCategory 1 = UnRead
decodeCategory 2 = Checked
decodeCategory 3 = Topic
decodeCategory 4 = Favorite
decodeCategory _ = UnRead
cat2score :: Category -> Int
cat2score Trash = 0
cat2score UnRead = 1
cat2score Checked = 2
cat2score Topic = 3
cat2score Favorite = 4
-- caroussel :: Category -> R.Element -- caroussel :: Category -> R.Element
caroussel session nodeId setLocalCategories r cat = H.div {className:"flex"} divs caroussel :: R2.Component CarousselProps
caroussel = R.createElement carousselCpt
carousselCpt :: R.Component CarousselProps
carousselCpt = R.hooksComponentWithModule thisModule "caroussel" cpt
where
cpt { category, nodeId, row: DocumentsView r, session, setLocalCategories } _ = do
pure $ H.div {className:"flex"} divs
where where
divs = map (\c -> if cat == c divs = map (\c -> if category == c
then then
H.div { className : icon c (cat == c) } [] H.div { className : icon c (category == c) } []
else else
H.div { className : icon c (cat == c) H.div { className : icon c (category == c)
, on: { click: onClick c} , on: { click: onClick c}
} [] } []
) (caroussel' cat) ) (caroussel' category)
caroussel' :: Category -> Array Category caroussel' :: Category -> Array Category
caroussel' Trash = A.take 2 categories caroussel' Trash = A.take 2 categories
......
module Gargantext.Components.Category.Types where
import Data.Argonaut (class DecodeJson, class EncodeJson, decodeJson, encodeJson)
import Data.Generic.Rep (class Generic)
import Data.Generic.Rep.Eq (genericEq)
import Data.Generic.Rep.Show (genericShow)
import Gargantext.Prelude
------------------------------------------------------------------------
data Category = Trash | UnRead | Checked | Topic | Favorite
categories :: Array Category
categories = [Trash, UnRead, Checked, Topic, Favorite]
derive instance genericFavorite :: Generic Category _
instance showCategory :: Show Category where
show = genericShow
instance eqCategory :: Eq Category where
eq = genericEq
instance decodeJsonCategory :: DecodeJson Category where
decodeJson json = do
obj <- decodeJson json
pure $ decodeCategory obj
instance encodeJsonCategory :: EncodeJson Category where
encodeJson cat = encodeJson (cat2score cat)
favCategory :: Category -> Category
favCategory Favorite = Topic
favCategory _ = Favorite
trashCategory :: Category -> Category
trashCategory _ = Trash
-- TODO: ?
--trashCategory Trash = UnRead
decodeCategory :: Int -> Category
decodeCategory 0 = Trash
decodeCategory 1 = UnRead
decodeCategory 2 = Checked
decodeCategory 3 = Topic
decodeCategory 4 = Favorite
decodeCategory _ = UnRead
cat2score :: Category -> Int
cat2score Trash = 0
cat2score UnRead = 1
cat2score Checked = 2
cat2score Topic = 3
cat2score Favorite = 4
...@@ -21,22 +21,22 @@ import Reactix.DOM.HTML as HTML ...@@ -21,22 +21,22 @@ import Reactix.DOM.HTML as HTML
import Gargantext.Utils.Reactix as R2 import Gargantext.Utils.Reactix as R2
thisModule :: String
thisModule = "Gargantext.Components.ContextMenu.ContextMenu" thisModule = "Gargantext.Components.ContextMenu.ContextMenu"
type Props t = ( type Props t = (
x :: Number x :: Number
, y :: Number , y :: Number
, onClose :: Unit -> Effect Unit , onClose :: Effect Unit
, setMenu :: R.Setter (Maybe t)
) )
contextMenu :: forall t. Record (Props t) -> Array R.Element -> R.Element contextMenu :: forall t. R2.Component (Props t)
contextMenu = R.createElement contextMenuCpt contextMenu = R.createElement contextMenuCpt
contextMenuCpt :: forall t. R.Component (Props t) contextMenuCpt :: forall t. R.Component (Props t)
contextMenuCpt = R.hooksComponentWithModule thisModule "contextMenu" cpt contextMenuCpt = R.hooksComponentWithModule thisModule "contextMenu" cpt
where where
cpt menu@{ x, y, onClose, setMenu } children = do cpt menu@{ x, y, onClose } children = do
host <- R2.getPortalHost host <- R2.getPortalHost
root <- R.useRef null root <- R.useRef null
rect /\ setRect <- R.useState $ \_ -> Nothing rect /\ setRect <- R.useState $ \_ -> Nothing
...@@ -45,7 +45,7 @@ contextMenuCpt = R.hooksComponentWithModule thisModule "contextMenu" cpt ...@@ -45,7 +45,7 @@ contextMenuCpt = R.hooksComponentWithModule thisModule "contextMenu" cpt
(\r -> setRect (\_ -> Just (Element.boundingRect r))) (\r -> setRect (\_ -> Just (Element.boundingRect r)))
(toMaybe $ R.readRef root) (toMaybe $ R.readRef root)
pure $ pure unit pure $ pure unit
R.useLayoutEffect2 root rect (contextMenuEffect onClose setMenu root) R.useLayoutEffect2 root rect (contextMenuEffect onClose root)
let cs = [ let cs = [
HTML.div { className: "popover-content" } HTML.div { className: "popover-content" }
[ HTML.div { className: "panel panel-default" } [ HTML.div { className: "panel panel-default" }
...@@ -57,27 +57,28 @@ contextMenuCpt = R.hooksComponentWithModule thisModule "contextMenu" cpt ...@@ -57,27 +57,28 @@ contextMenuCpt = R.hooksComponentWithModule thisModule "contextMenu" cpt
pure $ R.createPortal [ elems root menu rect $ cs ] host pure $ R.createPortal [ elems root menu rect $ cs ] host
elems ref menu (Just rect) = HTML.div elems ref menu (Just rect) = HTML.div
{ ref { ref
, key: "context-menu"
, className: "context-menu" , className: "context-menu"
, style: position menu rect , style: position menu rect
, data: {toggle: "popover", placement: "right"} , data: {toggle: "popover", placement: "right"}
} }
elems ref _ _ = HTML.div elems ref _ _ = HTML.div
{ ref { ref
, key: "context-menu"
, className: "context-menu" , className: "context-menu"
, data: {toggle: "popover", placement: "right"} , data: {toggle: "popover", placement: "right"}
} }
contextMenuEffect contextMenuEffect
:: forall t. :: forall t.
(Unit -> Effect Unit) Effect Unit
-> R.Setter (Maybe t)
-> R.Ref (Nullable DOM.Element) -> R.Ref (Nullable DOM.Element)
-> Effect (Effect Unit) -> Effect (Effect Unit)
contextMenuEffect onClose setMenu rootRef = contextMenuEffect onClose rootRef =
case R.readNullableRef rootRef of case R.readNullableRef rootRef of
Just root -> do Just root -> do
let onClick = documentClickHandler onClose setMenu root let onClick = documentClickHandler onClose root
let onScroll = documentScrollHandler setMenu let onScroll = documentScrollHandler onClose
DOM.addEventListener document "click" onClick DOM.addEventListener document "click" onClick
DOM.addEventListener document "scroll" onScroll DOM.addEventListener document "scroll" onScroll
pure $ do pure $ do
...@@ -85,18 +86,14 @@ contextMenuEffect onClose setMenu rootRef = ...@@ -85,18 +86,14 @@ contextMenuEffect onClose setMenu rootRef =
DOM.removeEventListener document "scroll" onScroll DOM.removeEventListener document "scroll" onScroll
Nothing -> pure R.nothing Nothing -> pure R.nothing
documentClickHandler :: forall t. (Unit -> Effect Unit) -> R.Setter (Maybe t) -> DOM.Element -> Callback DE.MouseEvent documentClickHandler :: Effect Unit -> DOM.Element -> Callback DE.MouseEvent
documentClickHandler onClose hide menu = documentClickHandler onClose menu =
R2.named "hideMenuOnClickOutside" $ callback $ \e -> R2.named "hideMenuOnClickOutside" $ callback $ \e ->
if Element.contains menu (DE.target e) when (Element.contains menu (DE.target e)) onClose
then pure unit
else do documentScrollHandler :: Effect Unit -> Callback DE.MouseEvent
hide (const Nothing) documentScrollHandler onClose =
onClose unit R2.named "hideMenuOnScroll" $ callback $ \e -> onClose
documentScrollHandler :: forall t. R.Setter (Maybe t) -> Callback DE.MouseEvent
documentScrollHandler hide =
R2.named "hideMenuOnScroll" $ callback $ \e -> hide (const Nothing)
position :: forall t. Record (Props t) -> DOMRect -> { left :: Number, top :: Number } position :: forall t. Record (Props t) -> DOMRect -> { left :: Number, top :: Number }
position mouse {width: menuWidth, height: menuHeight} = {left, top} position mouse {width: menuWidth, height: menuHeight} = {left, top}
......
This diff is collapsed.
module Gargantext.Components.DocsTable.Types where
import Data.Argonaut (class DecodeJson, class EncodeJson, decodeJson, jsonEmptyObject, (.:), (:=), (~>))
import Data.Map (Map)
import Data.Map as Map
import Data.Maybe (Maybe(..))
import Data.Tuple (Tuple(..))
import Gargantext.Prelude
import Gargantext.Components.Category.Types (Category(..), decodeCategory)
data Action
= MarkCategory Int Category
newtype DocumentsView
= DocumentsView
{ _id :: Int
, category :: Category
, date :: Int
, ngramCount :: Maybe Int
, score :: Maybe Int
, source :: String
, title :: String
, url :: String
}
{-
derive instance genericDocumentsView :: Generic DocumentsView _
instance showDocumentsView :: Show DocumentsView where
show = genericShow
instance decodeJsonSearchType :: Argonaut.DecodeJson SearchType where
decodeJson = genericSumDecodeJson
instance encodeJsonSearchType :: Argonaut.EncodeJson SearchType where
encodeJson = genericSumEncodeJson
-}
instance decodeDocumentsView :: DecodeJson DocumentsView where
decodeJson json = do
obj <- decodeJson json
_id <- obj .: "id"
category <- obj .: "category"
date <- obj .: "date"
ngramCount <- obj .: "ngramCount"
score <- obj .: "score"
source <- obj .: "source"
title <- obj .: "title"
url <- obj .: "url"
pure $ DocumentsView { _id, category, date, ngramCount, score, source, title, url }
instance encodeDocumentsView :: EncodeJson DocumentsView where
encodeJson (DocumentsView dv) =
"id" := dv._id
~> "category" := dv.category
~> "date" := dv.date
~> "ngramCount" := dv.ngramCount
~> "score" := dv.score
~> "source" := dv.source
~> "title" := dv.title
~> "url" := dv.url
~> jsonEmptyObject
newtype Response = Response
{ cid :: Int
, hyperdata :: Hyperdata
, category :: Category
, ngramCount :: Maybe Int
, score :: Maybe Int
, title :: String
}
newtype Hyperdata = Hyperdata
{ title :: String
, source :: String
, pub_year :: Int
}
instance decodeHyperdata :: DecodeJson Hyperdata where
decodeJson json = do
obj <- decodeJson json
pub_year <- obj .: "publication_year"
source <- obj .: "source"
title <- obj .: "title"
pure $ Hyperdata { title,source, pub_year}
instance decodeResponse :: DecodeJson Response where
decodeJson json = do
obj <- decodeJson json
category <- obj .: "category"
cid <- obj .: "id"
hyperdata <- obj .: "hyperdata"
ngramCount <- obj .: "ngramCount"
score <- obj .: "score"
title <- obj .: "title"
pure $ Response { category: decodeCategory category, cid, hyperdata, ngramCount, score, title }
type LocalCategories = Map Int Category
type Query = String
---------------------------------------------------------
sampleData' :: DocumentsView
sampleData' = DocumentsView { _id : 1
, url : ""
, date : 2010
, title : "title"
, source : "source"
, category : UnRead
, ngramCount : Just 1
, score: Just 1 }
sampleData :: Array DocumentsView
--sampleData = replicate 10 sampleData'
sampleData = map (\(Tuple t s) -> DocumentsView { _id : 1
, url : ""
, date : 2017
, title: t
, source: s
, category : UnRead
, ngramCount : Just 10
, score: Just 1 }) sampleDocuments
sampleDocuments :: Array (Tuple String String)
sampleDocuments = [Tuple "Macroscopic dynamics of the fusion process" "Journal de Physique Lettres",Tuple "Effects of static and cyclic fatigue at high temperature upon reaction bonded silicon nitride" "Journal de Physique Colloques",Tuple "Reliability of metal/glass-ceramic junctions made by solid state bonding" "Journal de Physique Colloques",Tuple "High temperature mechanical properties and intergranular structure of sialons" "Journal de Physique Colloques",Tuple "SOLUTIONS OF THE LANDAU-VLASOV EQUATION IN NUCLEAR PHYSICS" "Journal de Physique Colloques",Tuple "A STUDY ON THE FUSION REACTION 139La + 12C AT 50 MeV/u WITH THE VUU EQUATION" "Journal de Physique Colloques",Tuple "Atomic structure of \"vitreous\" interfacial films in sialon" "Journal de Physique Colloques",Tuple "MICROSTRUCTURAL AND ANALYTICAL CHARACTERIZATION OF Al2O3/Al-Mg COMPOSITE INTERFACES" "Journal de Physique Colloques",Tuple "Development of oxidation resistant high temperature NbTiAl alloys and intermetallics" "Journal de Physique IV Colloque",Tuple "Determination of brazed joint constitutive law by inverse method" "Journal de Physique IV Colloque",Tuple "Two dimensional estimates from ocean SAR images" "Nonlinear Processes in Geophysics",Tuple "Comparison Between New Carbon Nanostructures Produced by Plasma with Industrial Carbon Black Grades" "Journal de Physique III",Tuple "<i>Letter to the Editor:</i> SCIPION, a new flexible ionospheric sounder in Senegal" "Annales Geophysicae",Tuple "Is reducibility in nuclear multifragmentation related to thermal scaling?" "Physics Letters B",Tuple "Independence of fragment charge distributions of the size of heavy multifragmenting sources" "Physics Letters B",Tuple "Hard photons and neutral pions as probes of hot and dense nuclear matter" "Nuclear Physics A",Tuple "Surveying the nuclear caloric curve" "Physics Letters B",Tuple "A hot expanding source in 50 A MeV Xe+Sn central reactions" "Physics Letters B"]
...@@ -22,7 +22,8 @@ import Prelude ...@@ -22,7 +22,8 @@ import Prelude
import Reactix as R import Reactix as R
import Reactix.DOM.HTML as H import Reactix.DOM.HTML as H
import Gargantext.Components.Category (Category(..), CategoryQuery(..), favCategory, decodeCategory, putCategories) import Gargantext.Components.Category (CategoryQuery(..), putCategories)
import Gargantext.Components.Category.Types (Category(..), decodeCategory, favCategory)
import Gargantext.Components.Search import Gargantext.Components.Search
import Gargantext.Components.Table as T import Gargantext.Components.Table as T
import Gargantext.Ends (url, Frontends) import Gargantext.Ends (url, Frontends)
...@@ -50,7 +51,9 @@ type Props = ...@@ -50,7 +51,9 @@ type Props =
) )
-- | Tracks the ids of documents to delete and that have been deleted -- | Tracks the ids of documents to delete and that have been deleted
type Deletions = { pending :: Set Int, deleted :: Set Int } type Deletions = { pending :: Set Int
, deleted :: Set Int
}
initialDeletions :: Deletions initialDeletions :: Deletions
initialDeletions = { pending: mempty, deleted: mempty } initialDeletions = { pending: mempty, deleted: mempty }
...@@ -108,7 +111,7 @@ docViewCpt = R.hooksComponentWithModule thisModule "docView" cpt ...@@ -108,7 +111,7 @@ docViewCpt = R.hooksComponentWithModule thisModule "docView" cpt
else else
snd path $ const ipp snd path $ const ipp
pure $ H.div { className: "container1" } pure $ H.div { className: "facets-doc-view container1" }
[ R2.row [ R2.row
[ chart [ chart
, H.div { className: "col-md-12" } , H.div { className: "col-md-12" }
...@@ -330,7 +333,10 @@ pageCpt = R.hooksComponentWithModule thisModule "page" cpt ...@@ -330,7 +333,10 @@ pageCpt = R.hooksComponentWithModule thisModule "page" cpt
, maybeStricken delete [ H.text source ] , maybeStricken delete [ H.text source ]
, maybeStricken delete [ H.text authors ] , maybeStricken delete [ H.text authors ]
-- , maybeStricken $ intercalate [comma] (pairUrl <$> pairs) -- , maybeStricken $ intercalate [comma] (pairUrl <$> pairs)
, H.input { type: "checkbox", checked: isChecked id, on: { click: toggleClick } } , H.input { defaultChecked: isChecked id
, on: { click: toggleClick }
, type: "checkbox"
}
] ]
, delete: true } , delete: true }
where where
......
module Gargantext.Components.Footer where
import Reactix as R
import Reactix.DOM.HTML as H
import Gargantext.Prelude
import Gargantext.Sessions as Sessions
thisModule :: String
thisModule = "Gargantext.Components.Footer"
---------------------------------------------------------------------------
type FooterProps =
(
session :: Sessions.Session
)
footer :: Record FooterProps -> R.Element
footer props = R.createElement footerCpt props []
footerCpt :: R.Component FooterProps
footerCpt = R.hooksComponentWithModule thisModule "footer" cpt
where
cpt { session } _ = do
pure $ H.div
{ className: "container" }
[ H.hr {}
, H.footer {} []
]
module Gargantext.Components.Forest where module Gargantext.Components.Forest where
import DOM.Simple.Console (log) import Data.Array as A
import Data.Tuple (fst)
import Data.Maybe (Maybe(..)) import Data.Maybe (Maybe(..), fromMaybe)
import Data.Set as Set import Data.Set as Set
import Data.Tuple (fst, snd) import Data.Tuple (fst, snd)
import Data.Tuple.Nested ((/\)) import Data.Tuple.Nested ((/\))
import DOM.Simple.Console (log, log2)
import Reactix as R
import Reactix.DOM.HTML as H
import Gargantext.AsyncTasks as GAT import Gargantext.AsyncTasks as GAT
import Gargantext.Components.Forest.Tree (treeView) import Gargantext.Components.Forest.Tree (treeView)
import Gargantext.Components.TopBar (topBar)
import Gargantext.Ends (Frontends, Backend(..)) import Gargantext.Ends (Frontends, Backend(..))
import Gargantext.Prelude import Gargantext.Prelude
import Gargantext.Routes (AppRoute) import Gargantext.Routes (AppRoute)
import Gargantext.Sessions (Session(..), Sessions, OpenNodes, unSessions) import Gargantext.Sessions (Session(..), Sessions, OpenNodes, unSessions)
import Gargantext.Types (Reload, Handed(..)) import Gargantext.Types (Reload, ReloadS, Handed(..))
import Gargantext.Utils.Reactix as R2 import Gargantext.Utils.Reactix as R2
import Reactix as R
import Reactix.DOM.HTML as H
thisModule :: String
thisModule = "Gargantext.Components.Forest" thisModule = "Gargantext.Components.Forest"
type Props = type Props = (
( frontends :: Frontends appReload :: ReloadS
, asyncTasksRef :: R.Ref (Maybe GAT.Reductor)
, backend :: R.State (Maybe Backend)
, frontends :: Frontends
, handed :: Handed , handed :: Handed
, reload :: R.State Int
, route :: AppRoute , route :: AppRoute
, sessions :: Sessions , sessions :: Sessions
, showLogin :: R.Setter Boolean , showLogin :: R.Setter Boolean
, backend :: R.State (Maybe Backend) , treeReloadRef :: R.Ref (Maybe ReloadS)
) )
forest :: Record Props -> R.Element forest :: R2.Component Props
forest props = R.createElement forestCpt props [] forest = R.createElement forestCpt
forestCpt :: R.Component Props forestCpt :: R.Component Props
forestCpt = R.hooksComponentWithModule thisModule "forest" cpt where forestCpt = R.hooksComponentWithModule thisModule "forest" cpt where
cpt { frontends, handed, reload: extReload, route, sessions, showLogin, backend} _ = do cpt { appReload
, asyncTasksRef
, backend
, frontends
, handed
, route
, sessions
, showLogin
, treeReloadRef } _ = do
-- NOTE: this is a hack to reload the tree view on demand -- NOTE: this is a hack to reload the tree view on demand
reload <- R.useState' (0 :: Reload) reload <- R.useState' (0 :: Reload)
asyncTasks <- GAT.useTasks appReload reload
openNodes <- R2.useLocalStorageState R2.openNodesKey (Set.empty :: OpenNodes) openNodes <- R2.useLocalStorageState R2.openNodesKey (Set.empty :: OpenNodes)
asyncTasks <- R2.useLocalStorageState GAT.localStorageKey GAT.empty
R2.useCache -- TODO If `treeReloadRef` is set, `reload` state should be updated
( frontends R.useEffect' $ do
R.setRef asyncTasksRef $ Just asyncTasks
case R.readRef treeReloadRef of
Nothing -> R.setRef treeReloadRef $ Just reload
Just _ -> pure unit
R2.useCache (
frontends
/\ route /\ route
/\ sessions /\ sessions
/\ fst openNodes /\ fst openNodes
/\ fst extReload /\ fst appReload
/\ fst reload /\ fst reload
/\ fst asyncTasks /\ (fst asyncTasks).storage
/\ handed /\ handed
) )
(cpt' openNodes asyncTasks reload showLogin backend) (cpt' openNodes asyncTasks appReload reload showLogin backend)
cpt' openNodes asyncTasks reload showLogin backend (frontends /\ route /\ sessions /\ _ /\ _ /\ _ /\ _ /\ handed) = do cpt' openNodes asyncTasks appReload reload showLogin backend (frontends /\ route /\ sessions /\ _ /\ _ /\ _ /\ _ /\ handed) = do
pure $ R2.row $ [plus handed showLogin backend] <> trees pure $ R2.row $ [plus handed showLogin backend] <> trees
where where
trees = tree <$> unSessions sessions trees = tree <$> unSessions sessions
tree s@(Session {treeId}) = tree s@(Session {treeId}) =
treeView { root: treeId treeView { appReload
, asyncTasks , asyncTasks
, frontends , frontends
, handed , handed
, mCurrentRoute: Just route , mCurrentRoute: Just route
, openNodes , openNodes
, reload , reload
, root: treeId
, session: s , session: s
} } []
plus :: Handed -> R.Setter Boolean -> R.State (Maybe Backend) -> R.Element plus :: Handed -> R.Setter Boolean -> R.State (Maybe Backend) -> R.Element
plus handed showLogin backend = H.div {className: if handed == RightHanded plus handed showLogin backend = H.div { className: handedClass } [
then "flex-start" -- TODO we should use lefthanded SASS class here
else "flex-end"
} [
H.button { title: "Add or remove connections to the server(s)." H.button { title: "Add or remove connections to the server(s)."
, on: {click} , on: {click}
, className: "btn btn-default" , className: "btn btn-default"
...@@ -85,5 +105,107 @@ plus handed showLogin backend = H.div {className: if handed == RightHanded ...@@ -85,5 +105,107 @@ plus handed showLogin backend = H.div {className: if handed == RightHanded
-- TODO same as the one in the Login Modal (same CSS) -- TODO same as the one in the Login Modal (same CSS)
-- [ H.i { className: "material-icons md-36"} [] ] -- [ H.i { className: "material-icons md-36"} [] ]
where where
handedClass = if handed == RightHanded then
"flex-start" -- TODO we should use lefthanded SASS class here
else
"flex-end"
click _ = (snd backend) (const Nothing) click _ = (snd backend) (const Nothing)
*> showLogin (const true) *> showLogin (const true)
-------------------------
type ForestLayoutProps = (
appReload :: ReloadS
, asyncTasksRef :: R.Ref (Maybe GAT.Reductor)
, backend :: R.State (Maybe Backend)
, frontends :: Frontends
, handed :: R.State Handed
, route :: AppRoute
, sessions :: Sessions
, showLogin :: R.Setter Boolean
, treeReloadRef :: R.Ref (Maybe ReloadS)
)
forestLayout :: R2.Component ForestLayoutProps
forestLayout props = R.createElement forestLayoutCpt props
forestLayoutCpt :: R.Component ForestLayoutProps
forestLayoutCpt = R.hooksComponentWithModule thisModule "forestLayout" cpt
where
cpt props@{ handed } children = do
pure $ R.fragment [ topBar { handed } [], forestLayoutMain props children ]
-- a component, for which first child element is placed inside the top bar
-- while the remaining ones are put into the main view
forestLayoutWithTopBar :: R2.Component ForestLayoutProps
forestLayoutWithTopBar props = R.createElement forestLayoutWithTopBarCpt props
forestLayoutWithTopBarCpt :: R.Component ForestLayoutProps
forestLayoutWithTopBarCpt = R.hooksComponentWithModule thisModule "forestLayoutWithTopBar" cpt
where
cpt props@{ handed } children = do
let { head: topBarChild, tail: mainChildren } =
fromMaybe { head: H.div {} [], tail: [] } $ A.uncons children
pure $ R.fragment [
topBar { handed } [ topBarChild ]
, forestLayoutMain props mainChildren
]
forestLayoutMain :: R2.Component ForestLayoutProps
forestLayoutMain props = R.createElement forestLayoutMainCpt props
forestLayoutMainCpt :: R.Component ForestLayoutProps
forestLayoutMainCpt = R.hooksComponentWithModule thisModule "forestLayoutMain" cpt
where
cpt props children = do
pure $ forestLayoutRaw props [
mainPage {} children
]
forestLayoutRaw :: R2.Component ForestLayoutProps
forestLayoutRaw props = R.createElement forestLayoutRawCpt props
forestLayoutRawCpt :: R.Component ForestLayoutProps
forestLayoutRawCpt = R.hooksComponentWithModule thisModule "forestLayoutRaw" cpt
where
cpt { appReload
, asyncTasksRef
, backend
, frontends
, handed
, route
, sessions
, showLogin
, treeReloadRef } children = do
let ordering =
case fst handed of
LeftHanded -> A.reverse
RightHanded -> identity
pure $ R2.row $ ordering ([
H.div { className: "col-md-2", style: { paddingTop: "60px" } } [
forest { appReload
, asyncTasksRef
, backend
, frontends
, handed: fst handed
, route
, sessions
, showLogin
, treeReloadRef } []
]
] <> children)
mainPage :: R2.Component ()
mainPage = R.createElement mainPageCpt
mainPageCpt :: R.Component ()
mainPageCpt = R.hooksComponentWithModule thisModule "mainPage" cpt
where
cpt {} children = do
pure $ H.div {className: "col-md-10"} [
H.div {id: "page-wrapper"} [
H.div {className: "container-fluid"} children
]
]
This diff is collapsed.
...@@ -3,13 +3,18 @@ module Gargantext.Components.Forest.Tree.Node where ...@@ -3,13 +3,18 @@ module Gargantext.Components.Forest.Tree.Node where
import Data.Array (reverse) import Data.Array (reverse)
import Data.Maybe (Maybe(..)) import Data.Maybe (Maybe(..))
import Data.Nullable (null) import Data.Nullable (null)
import Data.Tuple (snd)
import Data.Tuple.Nested ((/\)) import Data.Tuple.Nested ((/\))
import Effect (Effect)
import Effect.Aff (Aff, launchAff) import Effect.Aff (Aff, launchAff)
import Effect.Class (liftEffect) import Effect.Class (liftEffect)
import React.SyntheticEvent as E import React.SyntheticEvent as E
import Reactix as R import Reactix as R
import Reactix.DOM.HTML as H import Reactix.DOM.HTML as H
import Gargantext.Prelude
import Gargantext.AsyncTasks as GAT
import Gargantext.Components.Forest.Tree.Node.Settings (SettingsBox(..), settingsBox) import Gargantext.Components.Forest.Tree.Node.Settings (SettingsBox(..), settingsBox)
import Gargantext.Components.Forest.Tree.Node.Action (Action(..)) import Gargantext.Components.Forest.Tree.Node.Action (Action(..))
import Gargantext.Components.Forest.Tree.Node.Action.Upload.Types (FileType(..), UploadFileBlob(..)) import Gargantext.Components.Forest.Tree.Node.Action.Upload.Types (FileType(..), UploadFileBlob(..))
...@@ -17,7 +22,6 @@ import Gargantext.Components.Forest.Tree.Node.Action.Upload (DroppedFile(..), fi ...@@ -17,7 +22,6 @@ import Gargantext.Components.Forest.Tree.Node.Action.Upload (DroppedFile(..), fi
import Gargantext.Components.Forest.Tree.Node.Box (nodePopupView) import Gargantext.Components.Forest.Tree.Node.Box (nodePopupView)
import Gargantext.Components.Forest.Tree.Node.Box.Types (CommonProps) import Gargantext.Components.Forest.Tree.Node.Box.Types (CommonProps)
import Gargantext.Components.Forest.Tree.Node.Tools.ProgressBar (asyncProgressBar, BarType(..)) import Gargantext.Components.Forest.Tree.Node.Tools.ProgressBar (asyncProgressBar, BarType(..))
import Gargantext.Components.Forest.Tree.Node.Tools.Task (Tasks)
import Gargantext.Components.Forest.Tree.Node.Tools.Sync (nodeActionsGraph, nodeActionsNodeList) import Gargantext.Components.Forest.Tree.Node.Tools.Sync (nodeActionsGraph, nodeActionsNodeList)
import Gargantext.Components.Forest.Tree.Node.Tools (nodeLink) import Gargantext.Components.Forest.Tree.Node.Tools (nodeLink)
import Gargantext.Components.GraphExplorer.API as GraphAPI import Gargantext.Components.GraphExplorer.API as GraphAPI
...@@ -25,7 +29,6 @@ import Gargantext.Components.Lang (Lang(EN)) ...@@ -25,7 +29,6 @@ import Gargantext.Components.Lang (Lang(EN))
import Gargantext.Components.Nodes.Corpus (loadCorpusWithChild) import Gargantext.Components.Nodes.Corpus (loadCorpusWithChild)
import Gargantext.Ends (Frontends) import Gargantext.Ends (Frontends)
import Gargantext.Hooks.Loader (useLoader) import Gargantext.Hooks.Loader (useLoader)
import Gargantext.Prelude (Unit, bind, const, discard, map, pure, show, unit, void, ($), (<>), (==), identity)
import Gargantext.Routes as Routes import Gargantext.Routes as Routes
import Gargantext.Version as GV import Gargantext.Version as GV
import Gargantext.Sessions (Session, sessionId) import Gargantext.Sessions (Session, sessionId)
...@@ -34,66 +37,93 @@ import Gargantext.Types as GT ...@@ -34,66 +37,93 @@ import Gargantext.Types as GT
import Gargantext.Utils.Popover as Popover import Gargantext.Utils.Popover as Popover
import Gargantext.Utils.Reactix as R2 import Gargantext.Utils.Reactix as R2
thisModule :: String
thisModule = "Gargantext.Components.Forest.Tree.Node" thisModule = "Gargantext.Components.Forest.Tree.Node"
-- Main Node -- Main Node
type NodeMainSpanProps = type NodeMainSpanProps = (
( id :: ID appReload :: GT.ReloadS
, asyncTasks :: GAT.Reductor
, folderOpen :: R.State Boolean , folderOpen :: R.State Boolean
, frontends :: Frontends , frontends :: Frontends
, id :: ID
, isLeaf :: IsLeaf
, mCurrentRoute :: Maybe Routes.AppRoute , mCurrentRoute :: Maybe Routes.AppRoute
, name :: Name , name :: Name
, nodeType :: GT.NodeType , nodeType :: GT.NodeType
, tasks :: Record Tasks , setPopoverRef :: R.Ref (Maybe (Boolean -> Effect Unit))
| CommonProps | CommonProps
) )
type IsLeaf = Boolean type IsLeaf = Boolean
nodeMainSpan :: IsLeaf nodeSpan :: R2.Component NodeMainSpanProps
-> Record NodeMainSpanProps nodeSpan = R.createElement nodeSpanCpt
-> R.Element
nodeMainSpan isLeaf p@{ dispatch, folderOpen, frontends, handed, session } = R.createElement el p [] nodeSpanCpt :: R.Component NodeMainSpanProps
nodeSpanCpt = R.hooksComponentWithModule thisModule "nodeSpan" cpt
where
cpt props children = do
pure $ H.div {} ([ nodeMainSpan props [] ] <> children)
nodeMainSpan :: R2.Component NodeMainSpanProps
nodeMainSpan = R.createElement nodeMainSpanCpt
nodeMainSpanCpt :: R.Component NodeMainSpanProps
nodeMainSpanCpt = R.hooksComponentWithModule thisModule "nodeMainSpan" cpt
where where
el = R.hooksComponentWithModule thisModule "nodeMainSpan" cpt cpt props@{ appReload
cpt props@{id, mCurrentRoute, name, nodeType, tasks: { onTaskFinish, tasks }} _ = do , asyncTasks: (asyncTasks /\ dispatchAsyncTasks)
, dispatch
, folderOpen
, frontends
, handed
, id
, isLeaf
, mCurrentRoute
, name
, nodeType
, session
, setPopoverRef
} _ = do
-- only 1 popup at a time is allowed to be opened -- only 1 popup at a time is allowed to be opened
droppedFile <- R.useState' (Nothing :: Maybe DroppedFile) droppedFile <- R.useState' (Nothing :: Maybe DroppedFile)
isDragOver <- R.useState' false isDragOver <- R.useState' false
popoverRef <- R.useRef null popoverRef <- R.useRef null
R.useEffect' $ do
R.setRef setPopoverRef $ Just $ Popover.setOpen popoverRef
let ordering = let ordering =
case handed of case handed of
GT.LeftHanded -> reverse GT.LeftHanded -> reverse
GT.RightHanded -> identity GT.RightHanded -> identity
let isSelected = mCurrentRoute == Routes.nodeTypeAppRoute nodeType (sessionId session) id
pure $ H.span (dropProps droppedFile isDragOver) pure $ H.span (dropProps droppedFile isDragOver)
$ ordering $ ordering
[ folderIcon nodeType folderOpen [ folderIcon nodeType folderOpen
, chevronIcon isLeaf handed nodeType folderOpen , chevronIcon isLeaf handed nodeType folderOpen
, nodeLink { frontends , nodeLink { frontends
, id , handed
, folderOpen , folderOpen
, isSelected: mCurrentRoute , id
== Routes.nodeTypeAppRoute , isSelected
nodeType
(sessionId session) id
, name: name' props , name: name' props
, nodeType , nodeType
, session , session
, handed
} }
, fileTypeView { dispatch, droppedFile, id, isDragOver, nodeType } , fileTypeView { dispatch, droppedFile, id, isDragOver, nodeType }
, H.div {} (map (\t -> asyncProgressBar { asyncTask: t , H.div {} (map (\t -> asyncProgressBar { asyncTask: t
, barType: Pie , barType: Pie
, corpusId: id , nodeId: id
, onFinish: const $ onTaskFinish t , onFinish: onTaskFinish id t
, session , session
} }
) tasks ) $ GAT.getTasks asyncTasks id
) )
, if nodeType == GT.NodeUser , if nodeType == GT.NodeUser
then GV.versionView {session} then GV.versionView {session}
...@@ -110,7 +140,6 @@ nodeMainSpan isLeaf p@{ dispatch, folderOpen, frontends, handed, session } = R.c ...@@ -110,7 +140,6 @@ nodeMainSpan isLeaf p@{ dispatch, folderOpen, frontends, handed, session } = R.c
] ]
else H.div {} [] else H.div {} []
, nodeActions { id , nodeActions { id
, nodeType , nodeType
, refreshTree: const $ dispatch RefreshTree , refreshTree: const $ dispatch RefreshTree
...@@ -120,31 +149,40 @@ nodeMainSpan isLeaf p@{ dispatch, folderOpen, frontends, handed, session } = R.c ...@@ -120,31 +149,40 @@ nodeMainSpan isLeaf p@{ dispatch, folderOpen, frontends, handed, session } = R.c
] ]
where where
onTaskFinish id t _ = do
dispatchAsyncTasks $ GAT.Finish id t
snd appReload $ (_ + 1)
SettingsBox {show: showBox} = settingsBox nodeType SettingsBox {show: showBox} = settingsBox nodeType
onPopoverClose popoverRef _ = Popover.setOpen popoverRef false onPopoverClose popoverRef _ = Popover.setOpen popoverRef false
name' {name, nodeType} = if nodeType == GT.NodeUser name' {name, nodeType} = if nodeType == GT.NodeUser then show session else name
then show session
else name mNodePopupView props@{id, nodeType} onPopoverClose =
nodePopupView { dispatch
, handed : props.handed
, id
, name: name' props
, nodeType
, onPopoverClose
, session
}
chevronIcon isLeaf handed' nodeType folderOpen'@(open /\ _) = chevronIcon true handed' nodeType (open /\ setOpen) = H.div {} []
if isLeaf chevronIcon false handed' nodeType (open /\ setOpen) =
then H.div {} []
else
H.a { className: "chevron-icon" H.a { className: "chevron-icon"
, onClick: R2.effToggler folderOpen' , on: { click: \_ -> setOpen $ not }
} }
[ H.i { [ H.i { className: if open
className: if open
then "fa fa-chevron-down" then "fa fa-chevron-down"
else if handed' == GT.RightHanded else if handed' == GT.RightHanded
then "fa fa-chevron-right" then "fa fa-chevron-right"
else "fa fa-chevron-left" else "fa fa-chevron-left"
} [] ] } [] ]
folderIcon nodeType folderOpen'@(open /\ _) = folderIcon nodeType (open /\ setOpen) =
H.a { className: "folder-icon" H.a { className: "folder-icon"
, onClick: R2.effToggler folderOpen' , on: { click: \_ -> setOpen $ not }
} [ } [
H.i {className: GT.fldr nodeType open} [] H.i {className: GT.fldr nodeType open} []
] ]
...@@ -154,16 +192,6 @@ nodeMainSpan isLeaf p@{ dispatch, folderOpen, frontends, handed, session } = R.c ...@@ -154,16 +192,6 @@ nodeMainSpan isLeaf p@{ dispatch, folderOpen, frontends, handed, session } = R.c
<> "Click here to execute one of them." <> "Click here to execute one of them."
} [] } []
mNodePopupView props@{id, nodeType} onPopoverClose =
nodePopupView { id
, dispatch
, name: name' props
, nodeType
, onPopoverClose
, session
, handed : props.handed
}
dropProps droppedFile isDragOver = dropProps droppedFile isDragOver =
{ className: "leaf " <> (dropClass droppedFile isDragOver) { className: "leaf " <> (dropClass droppedFile isDragOver)
, on: { drop: dropHandler droppedFile , on: { drop: dropHandler droppedFile
......
...@@ -127,6 +127,7 @@ settingsBox Team = ...@@ -127,6 +127,7 @@ settingsBox Team =
, NodeFrameWrite , NodeFrameWrite
, NodeFrameCalc , NodeFrameCalc
, NodeFrameNotebook , NodeFrameNotebook
, Team
] ]
, Share , Share
, Delete , Delete
......
...@@ -6,6 +6,7 @@ import Data.Set (Set) ...@@ -6,6 +6,7 @@ import Data.Set (Set)
import Data.Set as Set import Data.Set as Set
import Data.String as S import Data.String as S
import Data.String.CodeUnits as DSCU import Data.String.CodeUnits as DSCU
import Data.Tuple (snd)
import Data.Tuple.Nested ((/\)) import Data.Tuple.Nested ((/\))
import Effect (Effect) import Effect (Effect)
import Effect.Aff (Aff, launchAff, launchAff_) import Effect.Aff (Aff, launchAff, launchAff_)
...@@ -24,6 +25,7 @@ import Gargantext.Utils (toggleSet) ...@@ -24,6 +25,7 @@ import Gargantext.Utils (toggleSet)
import Gargantext.Utils.Reactix as R2 import Gargantext.Utils.Reactix as R2
import Gargantext.Utils.ReactTooltip as ReactTooltip import Gargantext.Utils.ReactTooltip as ReactTooltip
thisModule :: String
thisModule = "Gargantext.Components.Forest.Tree.Node.Tools" thisModule = "Gargantext.Components.Forest.Tree.Node.Tools"
------------------------------------------------------------------------ ------------------------------------------------------------------------
...@@ -247,7 +249,7 @@ checkboxes :: forall a ...@@ -247,7 +249,7 @@ checkboxes :: forall a
-> R.Element -> R.Element
checkboxes xs (val /\ set) = checkboxes xs (val /\ set) =
H.fieldset {} $ map (\a -> H.div {} [ H.input { type: "checkbox" H.fieldset {} $ map (\a -> H.div {} [ H.input { type: "checkbox"
, checked: Set.member a val , defaultChecked: Set.member a val
, on: { click: \_ -> set , on: { click: \_ -> set
$ const $ const
$ toggleSet a val $ toggleSet a val
...@@ -282,11 +284,19 @@ nodeLink p = R.createElement nodeLinkCpt p [] ...@@ -282,11 +284,19 @@ nodeLink p = R.createElement nodeLinkCpt p []
nodeLinkCpt :: R.Component NodeLinkProps nodeLinkCpt :: R.Component NodeLinkProps
nodeLinkCpt = R.hooksComponentWithModule thisModule "nodeLink" cpt nodeLinkCpt = R.hooksComponentWithModule thisModule "nodeLink" cpt
where where
cpt { frontends, id, isSelected, name, nodeType, session, handed, folderOpen} _ = do cpt { folderOpen: (_ /\ setFolderOpen)
, frontends
, handed
, id
, isSelected
, name
, nodeType
, session
} _ = do
popoverRef <- R.useRef null popoverRef <- R.useRef null
pure $ pure $
H.div { onClick: R2.effToggler folderOpen } H.div { on: { click: onClick } }
[ H.a { data: { for: tooltipId [ H.a { data: { for: tooltipId
, tip: true , tip: true
} }
...@@ -305,6 +315,13 @@ nodeLinkCpt = R.hooksComponentWithModule thisModule "nodeLink" cpt ...@@ -305,6 +315,13 @@ nodeLinkCpt = R.hooksComponentWithModule thisModule "nodeLink" cpt
] ]
where where
-- NOTE Don't toggle tree if it is not selected
-- click on closed -> open
-- click on open -> ?
onClick _ = if isSelected then
setFolderOpen (const true)
else
setFolderOpen (const true)
tooltipId = "node-link-" <> show id tooltipId = "node-link-" <> show id
-- END node link -- END node link
......
...@@ -16,15 +16,16 @@ import Gargantext.Sessions (Session, get) ...@@ -16,15 +16,16 @@ import Gargantext.Sessions (Session, get)
import Gargantext.Types as GT import Gargantext.Types as GT
import Gargantext.Utils.Reactix as R2 import Gargantext.Utils.Reactix as R2
thisModule :: String
thisModule = "Gargantext.Components.Forest.Tree.Node.Tools.ProgressBar" thisModule = "Gargantext.Components.Forest.Tree.Node.Tools.ProgressBar"
data BarType = Bar | Pie data BarType = Bar | Pie
type Props = type Props = (
( asyncTask :: GT.AsyncTaskWithType asyncTask :: GT.AsyncTaskWithType
, barType :: BarType , barType :: BarType
, corpusId :: GT.ID , nodeId :: GT.ID
, onFinish :: Unit -> Effect Unit , onFinish :: Unit -> Effect Unit
, session :: Session , session :: Session
) )
...@@ -38,7 +39,7 @@ asyncProgressBarCpt = R.hooksComponentWithModule thisModule "asyncProgressBar" c ...@@ -38,7 +39,7 @@ asyncProgressBarCpt = R.hooksComponentWithModule thisModule "asyncProgressBar" c
where where
cpt props@{ asyncTask: (GT.AsyncTaskWithType {task: GT.AsyncTask {id}}) cpt props@{ asyncTask: (GT.AsyncTaskWithType {task: GT.AsyncTask {id}})
, barType , barType
, corpusId , nodeId
, onFinish , onFinish
} _ = do } _ = do
(progress /\ setProgress) <- R.useState' 0.0 (progress /\ setProgress) <- R.useState' 0.0
...@@ -104,13 +105,14 @@ queryProgress :: Record Props -> Aff GT.AsyncProgress ...@@ -104,13 +105,14 @@ queryProgress :: Record Props -> Aff GT.AsyncProgress
queryProgress { asyncTask: GT.AsyncTaskWithType { task: GT.AsyncTask {id} queryProgress { asyncTask: GT.AsyncTaskWithType { task: GT.AsyncTask {id}
, typ , typ
} }
, corpusId , nodeId
, session , session
} = get session (p typ) } = get session (p typ)
where where
-- TODO refactor path -- TODO refactor path
p GT.UpdateNode = NodeAPI GT.Node (Just corpusId) $ path <> id <> "/poll?limit=1" p GT.UpdateNode = NodeAPI GT.Node (Just nodeId) $ path <> id <> "/poll?limit=1"
p _ = NodeAPI GT.Corpus (Just corpusId) $ path <> id <> "/poll?limit=1" p GT.UpdateNgramsCharts = NodeAPI GT.Node (Just nodeId) $ path <> id <> "/poll?limit=1"
p _ = NodeAPI GT.Corpus (Just nodeId) $ path <> id <> "/poll?limit=1"
path = GT.asyncTaskTypePath typ path = GT.asyncTaskTypePath typ
-- TODO wait route: take the result if failure then message -- TODO wait route: take the result if failure then message
module Gargantext.Components.Forest.Tree.Node.Tools.Task
where
import Data.Array as A
import Data.Map as Map
import Data.Maybe (Maybe(..), maybe)
import Data.Tuple.Nested ((/\))
import Effect (Effect)
import Gargantext.AsyncTasks as GAT
import Gargantext.Prelude (Unit, discard, identity, ($), (+))
import Gargantext.Types (Reload)
import Gargantext.Types as GT
import Reactix as R
type Tasks =
( onTaskAdd :: GT.AsyncTaskWithType -> Effect Unit
, onTaskFinish :: GT.AsyncTaskWithType -> Effect Unit
, tasks :: Array GT.AsyncTaskWithType
)
tasksStruct :: Int
-> R.State GAT.Storage
-> R.State Reload
-> Record Tasks
tasksStruct id (asyncTasks /\ setAsyncTasks) (_ /\ setReload) =
{ onTaskAdd, onTaskFinish, tasks }
where
tasks = maybe [] identity $ Map.lookup id asyncTasks
onTaskAdd t = do
setReload (_ + 1)
setAsyncTasks $ Map.alter (maybe (Just [t])
$ (\ts -> Just $ A.cons t ts)) id
onTaskFinish t = do
setReload (_ + 1)
setAsyncTasks $ Map.alter (maybe Nothing $ (\ts -> Just $ GAT.removeTaskFromList ts t)) id
...@@ -20,6 +20,7 @@ import Reactix as R ...@@ -20,6 +20,7 @@ import Reactix as R
import Reactix.DOM.HTML as RH import Reactix.DOM.HTML as RH
import Record as Record import Record as Record
import Gargantext.AsyncTasks as GAT
import Gargantext.Components.Forest (forest) import Gargantext.Components.Forest (forest)
import Gargantext.Components.Graph as Graph import Gargantext.Components.Graph as Graph
import Gargantext.Components.GraphExplorer.Controls as Controls import Gargantext.Components.GraphExplorer.Controls as Controls
...@@ -40,20 +41,21 @@ import Gargantext.Utils.Reactix as R2 ...@@ -40,20 +41,21 @@ import Gargantext.Utils.Reactix as R2
thisModule :: String thisModule :: String
thisModule = "Gargantext.Components.GraphExplorer" thisModule = "Gargantext.Components.GraphExplorer"
type LayoutProps = type LayoutProps = (
( frontends :: Frontends asyncTasksRef :: R.Ref (Maybe GAT.Reductor)
, backend :: R.State (Maybe Backend)
, frontends :: Frontends
, graphId :: GET.GraphId , graphId :: GET.GraphId
, handed :: Types.Handed , handed :: Types.Handed
, mCurrentRoute :: AppRoute , mCurrentRoute :: AppRoute
, session :: Session , session :: Session
, sessions :: Sessions , sessions :: Sessions
, showLogin :: R.State Boolean , showLogin :: R.State Boolean
, backend :: R.State (Maybe Backend)
) )
type Props = type Props =
( graph :: SigmaxT.SGraph ( graph :: SigmaxT.SGraph
, graphVersion :: R.State Int , graphVersion :: Types.ReloadS
, hyperdataGraph :: GET.HyperdataGraph , hyperdataGraph :: GET.HyperdataGraph
, mMetaData :: Maybe GET.MetaData , mMetaData :: Maybe GET.MetaData
| LayoutProps | LayoutProps
...@@ -70,7 +72,7 @@ explorerLayoutCpt = R.hooksComponentWithModule thisModule "explorerLayout" cpt ...@@ -70,7 +72,7 @@ explorerLayoutCpt = R.hooksComponentWithModule thisModule "explorerLayout" cpt
graphVersion <- R.useState' 0 graphVersion <- R.useState' 0
pure $ explorerLayoutView graphVersion props pure $ explorerLayoutView graphVersion props
explorerLayoutView :: R.State Int -> Record LayoutProps -> R.Element explorerLayoutView :: Types.ReloadS -> Record LayoutProps -> R.Element
explorerLayoutView graphVersion p = R.createElement el p [] explorerLayoutView graphVersion p = R.createElement el p []
where where
el = R.hooksComponentWithModule thisModule "explorerLayoutView" cpt el = R.hooksComponentWithModule thisModule "explorerLayoutView" cpt
...@@ -90,7 +92,9 @@ explorer props = R.createElement explorerCpt props [] ...@@ -90,7 +92,9 @@ explorer props = R.createElement explorerCpt props []
explorerCpt :: R.Component Props explorerCpt :: R.Component Props
explorerCpt = R.hooksComponentWithModule thisModule "explorer" cpt explorerCpt = R.hooksComponentWithModule thisModule "explorer" cpt
where where
cpt props@{ frontends cpt props@{ asyncTasksRef
, backend
, frontends
, graph , graph
, graphId , graphId
, graphVersion , graphVersion
...@@ -101,7 +105,6 @@ explorerCpt = R.hooksComponentWithModule thisModule "explorer" cpt ...@@ -101,7 +105,6 @@ explorerCpt = R.hooksComponentWithModule thisModule "explorer" cpt
, session , session
, sessions , sessions
, showLogin , showLogin
, backend
} _ = do } _ = do
let startForceAtlas = maybe true (\(GET.MetaData { startForceAtlas }) -> startForceAtlas) mMetaData let startForceAtlas = maybe true (\(GET.MetaData { startForceAtlas }) -> startForceAtlas) mMetaData
...@@ -114,6 +117,7 @@ explorerCpt = R.hooksComponentWithModule thisModule "explorer" cpt ...@@ -114,6 +117,7 @@ explorerCpt = R.hooksComponentWithModule thisModule "explorer" cpt
graphRef <- R.useRef null graphRef <- R.useRef null
graphVersionRef <- R.useRef (fst graphVersion) graphVersionRef <- R.useRef (fst graphVersion)
treeReload <- R.useState' 0 treeReload <- R.useState' 0
treeReloadRef <- R.useRef $ Just treeReload
controls <- Controls.useGraphControls { forceAtlasS controls <- Controls.useGraphControls { forceAtlasS
, graph , graph
, graphId , graphId
...@@ -154,14 +158,17 @@ explorerCpt = R.hooksComponentWithModule thisModule "explorer" cpt ...@@ -154,14 +158,17 @@ explorerCpt = R.hooksComponentWithModule thisModule "explorer" cpt
[ inner handed [ inner handed
[ rowControls [ Controls.controls controls ] [ rowControls [ Controls.controls controls ]
, R2.row $ mainLayout handed $ , R2.row $ mainLayout handed $
tree { frontends tree { asyncTasksRef
, backend
, frontends
, handed , handed
, mCurrentRoute , mCurrentRoute
, reload: treeReload , reload: treeReload
, sessions , sessions
, show: fst controls.showTree , show: fst controls.showTree
, showLogin: snd showLogin , showLogin: snd showLogin
, backend} , treeReloadRef
}
/\ /\
RH.div { ref: graphRef, id: "graph-view", className: "col-md-12" } [] RH.div { ref: graphRef, id: "graph-view", className: "col-md-12" } []
/\ /\
...@@ -208,9 +215,17 @@ explorerCpt = R.hooksComponentWithModule thisModule "explorer" cpt ...@@ -208,9 +215,17 @@ explorerCpt = R.hooksComponentWithModule thisModule "explorer" cpt
tree :: Record TreeProps -> R.Element tree :: Record TreeProps -> R.Element
tree { show: false } = RH.div { id: "tree" } [] tree { show: false } = RH.div { id: "tree" } []
tree { frontends, handed, mCurrentRoute: route, reload, sessions, showLogin, backend} = tree { asyncTasksRef, backend, frontends, handed, mCurrentRoute: route, reload, sessions, showLogin, treeReloadRef } =
RH.div {className: "col-md-2 graph-tree"} [ RH.div {className: "col-md-2 graph-tree"} [
forest { frontends, handed, reload, route, sessions, showLogin, backend} forest { appReload: reload
, asyncTasksRef
, backend
, frontends
, handed
, route
, sessions
, showLogin
, treeReloadRef } []
] ]
mSidebar :: Maybe GET.MetaData mSidebar :: Maybe GET.MetaData
...@@ -222,26 +237,28 @@ explorerCpt = R.hooksComponentWithModule thisModule "explorer" cpt ...@@ -222,26 +237,28 @@ explorerCpt = R.hooksComponentWithModule thisModule "explorer" cpt
type TreeProps = type TreeProps =
( (
frontends :: Frontends asyncTasksRef :: R.Ref (Maybe GAT.Reductor)
, backend :: R.State (Maybe Backend)
, frontends :: Frontends
, handed :: Types.Handed , handed :: Types.Handed
, mCurrentRoute :: AppRoute , mCurrentRoute :: AppRoute
, reload :: R.State Int , reload :: Types.ReloadS
, sessions :: Sessions , sessions :: Sessions
, show :: Boolean , show :: Boolean
, showLogin :: R.Setter Boolean , showLogin :: R.Setter Boolean
, backend :: R.State (Maybe Backend) , treeReloadRef :: R.Ref (Maybe Types.ReloadS)
) )
type MSidebarProps = type MSidebarProps =
( frontends :: Frontends ( frontends :: Frontends
, graph :: SigmaxT.SGraph , graph :: SigmaxT.SGraph
, graphId :: GET.GraphId , graphId :: GET.GraphId
, graphVersion :: R.State Int , graphVersion :: Types.ReloadS
, removedNodeIds :: R.State SigmaxT.NodeIds , removedNodeIds :: R.State SigmaxT.NodeIds
, showSidePanel :: R.State GET.SidePanelState , showSidePanel :: R.State GET.SidePanelState
, selectedNodeIds :: R.State SigmaxT.NodeIds , selectedNodeIds :: R.State SigmaxT.NodeIds
, session :: Session , session :: Session
, treeReload :: R.State Int , treeReload :: Types.ReloadS
) )
type GraphProps = ( type GraphProps = (
...@@ -349,7 +366,7 @@ modeGraphType Types.Sources = "star" ...@@ -349,7 +366,7 @@ modeGraphType Types.Sources = "star"
modeGraphType Types.Terms = "def" modeGraphType Types.Terms = "def"
getNodes :: Session -> R.State Int -> GET.GraphId -> Aff GET.HyperdataGraph getNodes :: Session -> Types.ReloadS -> GET.GraphId -> Aff GET.HyperdataGraph
getNodes session (graphVersion /\ _) graphId = getNodes session (graphVersion /\ _) graphId =
get session $ NodeAPI Types.Graph get session $ NodeAPI Types.Graph
(Just graphId) (Just graphId)
......
...@@ -17,7 +17,7 @@ controlsToggleButton :: Record Props -> R.Element ...@@ -17,7 +17,7 @@ controlsToggleButton :: Record Props -> R.Element
controlsToggleButton props = R.createElement controlsToggleButtonCpt props [] controlsToggleButton props = R.createElement controlsToggleButtonCpt props []
controlsToggleButtonCpt :: R.Component Props controlsToggleButtonCpt :: R.Component Props
controlsToggleButtonCpt = R.hooksComponentWithModule thisModule "graphControlsToggleButton" cpt controlsToggleButtonCpt = R.hooksComponentWithModule thisModule "controlsToggleButton" cpt
where where
cpt {state} _ = do cpt {state} _ = do
let (open /\ setOpen) = state let (open /\ setOpen) = state
......
...@@ -32,7 +32,7 @@ import Gargantext.Data.Array (mapMaybe) ...@@ -32,7 +32,7 @@ import Gargantext.Data.Array (mapMaybe)
import Gargantext.Ends (Frontends) import Gargantext.Ends (Frontends)
import Gargantext.Hooks.Sigmax.Types as SigmaxT import Gargantext.Hooks.Sigmax.Types as SigmaxT
import Gargantext.Sessions (Session) import Gargantext.Sessions (Session)
import Gargantext.Types (CTabNgramType, TabSubType(..), TabType(..), TermList(..), modeTabType) import Gargantext.Types (CTabNgramType, ReloadS, TabSubType(..), TabType(..), TermList(..), modeTabType)
import Gargantext.Utils.Reactix as R2 import Gargantext.Utils.Reactix as R2
import Partial.Unsafe (unsafePartial) import Partial.Unsafe (unsafePartial)
...@@ -42,13 +42,13 @@ type Props = ...@@ -42,13 +42,13 @@ type Props =
( frontends :: Frontends ( frontends :: Frontends
, graph :: SigmaxT.SGraph , graph :: SigmaxT.SGraph
, graphId :: Int , graphId :: Int
, graphVersion :: R.State Int , graphVersion :: ReloadS
, metaData :: GET.MetaData , metaData :: GET.MetaData
, removedNodeIds :: R.State SigmaxT.NodeIds , removedNodeIds :: R.State SigmaxT.NodeIds
, selectedNodeIds :: R.State SigmaxT.NodeIds , selectedNodeIds :: R.State SigmaxT.NodeIds
, session :: Session , session :: Session
, showSidePanel :: R.State GET.SidePanelState , showSidePanel :: R.State GET.SidePanelState
, treeReload :: R.State Int , treeReload :: ReloadS
) )
sidebar :: Record Props -> R.Element sidebar :: Record Props -> R.Element
...@@ -110,7 +110,7 @@ sideTab (Opened SideTabData) props = ...@@ -110,7 +110,7 @@ sideTab (Opened SideTabData) props =
[ RH.span {} [ RH.text text ] [ RH.span {} [ RH.text text ]
, RH.input { type: "checkbox" , RH.input { type: "checkbox"
, className: "checkbox" , className: "checkbox"
, checked: true , defaultChecked: true
, title: "Mark as completed" } ] , title: "Mark as completed" } ]
...@@ -204,7 +204,7 @@ type DeleteNodes = ...@@ -204,7 +204,7 @@ type DeleteNodes =
, nodes :: Array (Record SigmaxT.Node) , nodes :: Array (Record SigmaxT.Node)
, session :: Session , session :: Session
, termList :: TermList , termList :: TermList
, treeReload :: R.State Int , treeReload :: ReloadS
) )
deleteNodes :: Record DeleteNodes -> Effect Unit deleteNodes :: Record DeleteNodes -> Effect Unit
...@@ -223,7 +223,10 @@ deleteNode :: TermList ...@@ -223,7 +223,10 @@ deleteNode :: TermList
-> GET.MetaData -> GET.MetaData
-> Record SigmaxT.Node -> Record SigmaxT.Node
-> Aff NTC.VersionedNgramsPatches -> Aff NTC.VersionedNgramsPatches
deleteNode termList session (GET.MetaData metaData) node = NTC.putNgramsPatches coreParams versioned deleteNode termList session (GET.MetaData metaData) node = do
ret <- NTC.putNgramsPatches coreParams versioned
task <- NTC.postNgramsChartsAsync coreParams -- TODO add task
pure ret
where where
nodeId :: Int nodeId :: Int
nodeId = unsafePartial $ fromJust $ fromString node.id nodeId = unsafePartial $ fromJust $ fromString node.id
......
...@@ -10,6 +10,7 @@ import Reactix as R ...@@ -10,6 +10,7 @@ import Reactix as R
import Gargantext.Components.LoadingSpinner (loadingSpinner) import Gargantext.Components.LoadingSpinner (loadingSpinner)
import Gargantext.Utils.Reactix as R2 import Gargantext.Utils.Reactix as R2
thisModule :: String
thisModule = "Gargantext.Components.Loader" thisModule = "Gargantext.Components.Loader"
type Props path loaded = type Props path loaded =
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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