Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
P
purescript-gargantext
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Grégoire Locqueville
purescript-gargantext
Commits
313c616d
Commit
313c616d
authored
Nov 23, 2022
by
arturo
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
>>> continue
parent
c4060538
Changes
13
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
837 additions
and
269 deletions
+837
-269
bootstrap-darkster.css
dist/styles/bootstrap-darkster.css
+65
-0
bootstrap-default.css
dist/styles/bootstrap-default.css
+64
-0
bootstrap-greyson.css
dist/styles/bootstrap-greyson.css
+65
-0
bootstrap-herbie.css
dist/styles/bootstrap-herbie.css
+65
-0
bootstrap-monotony.css
dist/styles/bootstrap-monotony.css
+65
-0
Forms.purs
src/Gargantext/Components/Forms.purs
+0
-24
Login.purs
src/Gargantext/Components/Login.purs
+112
-69
ForgotPassword.purs
src/Gargantext/Components/Login/ForgotPassword.purs
+6
-7
Form.purs
src/Gargantext/Components/Login/Form.purs
+308
-168
Types.purs
src/Gargantext/Components/Login/Types.purs
+1
-1
Boxed.purs
src/Gargantext/Hooks/FormValidation/Boxed.purs
+11
-0
Unboxed.purs
src/Gargantext/Hooks/FormValidation/Unboxed.purs
+7
-0
_login.sass
src/sass/_legacy/_login.sass
+68
-0
No files found.
dist/styles/bootstrap-darkster.css
View file @
313c616d
...
@@ -9699,6 +9699,71 @@ input[type=range]:-moz-focusring {
...
@@ -9699,6 +9699,71 @@ input[type=range]:-moz-focusring {
gap
:
28px
;
gap
:
28px
;
}
}
.login-modal-form__title
{
position
:
relative
;
background-color
:
#dee2e6
;
padding
:
0.75rem
1.25rem
;
text-align
:
center
;
margin-top
:
-1rem
;
margin-left
:
-1rem
;
margin-right
:
-1rem
;
}
.login-modal-form__title__return
{
top
:
50%
;
left
:
50%
;
transform
:
translateX
(
-50%
)
translateY
(
-50%
);
position
:
absolute
;
left
:
28px
;
}
.login-modal-form__title__text
{
font-family
:
SFMono-Regular
,
Menlo
,
Monaco
,
Consolas
,
"Liberation Mono"
,
"Courier New"
,
monospace
;
font-size
:
20px
;
font-weight
:
bold
;
}
.login-modal-form__separator
{
padding
:
0.75rem
calc
(
2
*
1.25rem
);
position
:
relative
;
}
.login-modal-form__separator__text
{
top
:
50%
;
left
:
50%
;
transform
:
translateX
(
-50%
)
translateY
(
-50%
);
position
:
absolute
;
display
:
inline-block
;
padding-left
:
32px
;
padding-right
:
32px
;
font-family
:
"Comfortaa"
;
font-size
:
24px
;
background-color
:
#fff
;
}
.login-modal-form__request-access
{
margin-top
:
calc
(
3
*
0.75rem
);
margin-left
:
auto
;
margin-right
:
auto
;
margin-bottom
:
0.75rem
;
padding
:
0.5rem
1rem
;
width
:
200px
;
display
:
block
;
}
.login-modal-form__log-in
{
padding
:
0.5rem
1rem
;
width
:
200px
;
margin-bottom
:
calc
(
2
*
0.75rem
);
margin-left
:
auto
;
margin-right
:
auto
;
margin-top
:
0.75rem
;
display
:
block
;
}
.login-modal-form__form
{
margin
:
0
auto
;
width
:
520px
;
}
.login-modal-form__error
{
margin-bottom
:
24px
;
color
:
#FF304F
;
text-align
:
center
;
}
.maintree
{
.maintree
{
position
:
relative
;
position
:
relative
;
animation
:
15ms
fade-in
;
animation
:
15ms
fade-in
;
...
...
dist/styles/bootstrap-default.css
View file @
313c616d
...
@@ -9648,6 +9648,70 @@ input[type=range]:-moz-focusring {
...
@@ -9648,6 +9648,70 @@ input[type=range]:-moz-focusring {
gap
:
28px
;
gap
:
28px
;
}
}
.login-modal-form__title
{
position
:
relative
;
background-color
:
#dee2e6
;
padding
:
0.75rem
1.25rem
;
text-align
:
center
;
margin-top
:
-1rem
;
margin-left
:
-1rem
;
margin-right
:
-1rem
;
}
.login-modal-form__title__return
{
top
:
50%
;
left
:
50%
;
transform
:
translateX
(
-50%
)
translateY
(
-50%
);
position
:
absolute
;
left
:
28px
;
}
.login-modal-form__title__text
{
font-family
:
SFMono-Regular
,
Menlo
,
Monaco
,
Consolas
,
"Liberation Mono"
,
"Courier New"
,
monospace
;
font-size
:
20px
;
font-weight
:
bold
;
}
.login-modal-form__separator
{
padding
:
0.75rem
calc
(
2
*
1.25rem
);
position
:
relative
;
}
.login-modal-form__separator__text
{
top
:
50%
;
left
:
50%
;
transform
:
translateX
(
-50%
)
translateY
(
-50%
);
position
:
absolute
;
display
:
inline-block
;
padding-left
:
32px
;
padding-right
:
32px
;
font-size
:
24px
;
background-color
:
#fff
;
}
.login-modal-form__request-access
{
margin-top
:
calc
(
3
*
0.75rem
);
margin-left
:
auto
;
margin-right
:
auto
;
margin-bottom
:
0.75rem
;
padding
:
0.5rem
1rem
;
width
:
200px
;
display
:
block
;
}
.login-modal-form__log-in
{
padding
:
0.5rem
1rem
;
width
:
200px
;
margin-bottom
:
calc
(
2
*
0.75rem
);
margin-left
:
auto
;
margin-right
:
auto
;
margin-top
:
0.75rem
;
display
:
block
;
}
.login-modal-form__form
{
margin
:
0
auto
;
width
:
520px
;
}
.login-modal-form__error
{
margin-bottom
:
24px
;
color
:
#dc3545
;
text-align
:
center
;
}
.maintree
{
.maintree
{
position
:
relative
;
position
:
relative
;
animation
:
15ms
fade-in
;
animation
:
15ms
fade-in
;
...
...
dist/styles/bootstrap-greyson.css
View file @
313c616d
...
@@ -9408,6 +9408,71 @@ input[type=range]:-moz-focusring {
...
@@ -9408,6 +9408,71 @@ input[type=range]:-moz-focusring {
gap
:
28px
;
gap
:
28px
;
}
}
.login-modal-form__title
{
position
:
relative
;
background-color
:
#dee2e6
;
padding
:
0.75rem
1.25rem
;
text-align
:
center
;
margin-top
:
-1rem
;
margin-left
:
-1rem
;
margin-right
:
-1rem
;
}
.login-modal-form__title__return
{
top
:
50%
;
left
:
50%
;
transform
:
translateX
(
-50%
)
translateY
(
-50%
);
position
:
absolute
;
left
:
28px
;
}
.login-modal-form__title__text
{
font-family
:
SFMono-Regular
,
Menlo
,
Monaco
,
Consolas
,
"Liberation Mono"
,
"Courier New"
,
monospace
;
font-size
:
20px
;
font-weight
:
bold
;
}
.login-modal-form__separator
{
padding
:
0.75rem
calc
(
2
*
1.25rem
);
position
:
relative
;
}
.login-modal-form__separator__text
{
top
:
50%
;
left
:
50%
;
transform
:
translateX
(
-50%
)
translateY
(
-50%
);
position
:
absolute
;
display
:
inline-block
;
padding-left
:
32px
;
padding-right
:
32px
;
font-family
:
"Oswald"
;
font-size
:
24px
;
background-color
:
#fff
;
}
.login-modal-form__request-access
{
margin-top
:
calc
(
3
*
0.75rem
);
margin-left
:
auto
;
margin-right
:
auto
;
margin-bottom
:
0.75rem
;
padding
:
0.5rem
1rem
;
width
:
200px
;
display
:
block
;
}
.login-modal-form__log-in
{
padding
:
0.5rem
1rem
;
width
:
200px
;
margin-bottom
:
calc
(
2
*
0.75rem
);
margin-left
:
auto
;
margin-right
:
auto
;
margin-top
:
0.75rem
;
display
:
block
;
}
.login-modal-form__form
{
margin
:
0
auto
;
width
:
520px
;
}
.login-modal-form__error
{
margin-bottom
:
24px
;
color
:
#cc330d
;
text-align
:
center
;
}
.maintree
{
.maintree
{
position
:
relative
;
position
:
relative
;
animation
:
15ms
fade-in
;
animation
:
15ms
fade-in
;
...
...
dist/styles/bootstrap-herbie.css
View file @
313c616d
...
@@ -9656,6 +9656,71 @@ input[type=range]:-moz-focusring {
...
@@ -9656,6 +9656,71 @@ input[type=range]:-moz-focusring {
gap
:
28px
;
gap
:
28px
;
}
}
.login-modal-form__title
{
position
:
relative
;
background-color
:
#dee2e6
;
padding
:
0.75rem
1.25rem
;
text-align
:
center
;
margin-top
:
-1rem
;
margin-left
:
-1rem
;
margin-right
:
-1rem
;
}
.login-modal-form__title__return
{
top
:
50%
;
left
:
50%
;
transform
:
translateX
(
-50%
)
translateY
(
-50%
);
position
:
absolute
;
left
:
28px
;
}
.login-modal-form__title__text
{
font-family
:
SFMono-Regular
,
Menlo
,
Monaco
,
Consolas
,
"Liberation Mono"
,
"Courier New"
,
monospace
;
font-size
:
20px
;
font-weight
:
bold
;
}
.login-modal-form__separator
{
padding
:
0.75rem
calc
(
2
*
1.25rem
);
position
:
relative
;
}
.login-modal-form__separator__text
{
top
:
50%
;
left
:
50%
;
transform
:
translateX
(
-50%
)
translateY
(
-50%
);
position
:
absolute
;
display
:
inline-block
;
padding-left
:
32px
;
padding-right
:
32px
;
font-family
:
"Crete Round"
;
font-size
:
24px
;
background-color
:
#fff
;
}
.login-modal-form__request-access
{
margin-top
:
calc
(
3
*
0.75rem
);
margin-left
:
auto
;
margin-right
:
auto
;
margin-bottom
:
0.75rem
;
padding
:
0.5rem
1rem
;
width
:
200px
;
display
:
block
;
}
.login-modal-form__log-in
{
padding
:
0.5rem
1rem
;
width
:
200px
;
margin-bottom
:
calc
(
2
*
0.75rem
);
margin-left
:
auto
;
margin-right
:
auto
;
margin-top
:
0.75rem
;
display
:
block
;
}
.login-modal-form__form
{
margin
:
0
auto
;
width
:
520px
;
}
.login-modal-form__error
{
margin-bottom
:
24px
;
color
:
#FF4057
;
text-align
:
center
;
}
.maintree
{
.maintree
{
position
:
relative
;
position
:
relative
;
animation
:
15ms
fade-in
;
animation
:
15ms
fade-in
;
...
...
dist/styles/bootstrap-monotony.css
View file @
313c616d
...
@@ -9657,6 +9657,71 @@ input[type=range]:-moz-focusring {
...
@@ -9657,6 +9657,71 @@ input[type=range]:-moz-focusring {
gap
:
28px
;
gap
:
28px
;
}
}
.login-modal-form__title
{
position
:
relative
;
background-color
:
#dee2e6
;
padding
:
0.75rem
1.25rem
;
text-align
:
center
;
margin-top
:
-1rem
;
margin-left
:
-1rem
;
margin-right
:
-1rem
;
}
.login-modal-form__title__return
{
top
:
50%
;
left
:
50%
;
transform
:
translateX
(
-50%
)
translateY
(
-50%
);
position
:
absolute
;
left
:
28px
;
}
.login-modal-form__title__text
{
font-family
:
SFMono-Regular
,
Menlo
,
Monaco
,
Consolas
,
"Liberation Mono"
,
"Courier New"
,
monospace
;
font-size
:
20px
;
font-weight
:
bold
;
}
.login-modal-form__separator
{
padding
:
0.75rem
calc
(
2
*
1.25rem
);
position
:
relative
;
}
.login-modal-form__separator__text
{
top
:
50%
;
left
:
50%
;
transform
:
translateX
(
-50%
)
translateY
(
-50%
);
position
:
absolute
;
display
:
inline-block
;
padding-left
:
32px
;
padding-right
:
32px
;
font-family
:
"Open Sans"
;
font-size
:
24px
;
background-color
:
#fff
;
}
.login-modal-form__request-access
{
margin-top
:
calc
(
3
*
0.75rem
);
margin-left
:
auto
;
margin-right
:
auto
;
margin-bottom
:
0.75rem
;
padding
:
0.5rem
1rem
;
width
:
200px
;
display
:
block
;
}
.login-modal-form__log-in
{
padding
:
0.5rem
1rem
;
width
:
200px
;
margin-bottom
:
calc
(
2
*
0.75rem
);
margin-left
:
auto
;
margin-right
:
auto
;
margin-top
:
0.75rem
;
display
:
block
;
}
.login-modal-form__form
{
margin
:
0
auto
;
width
:
520px
;
}
.login-modal-form__error
{
margin-bottom
:
24px
;
color
:
#434343
;
text-align
:
center
;
}
.maintree
{
.maintree
{
position
:
relative
;
position
:
relative
;
animation
:
15ms
fade-in
;
animation
:
15ms
fade-in
;
...
...
src/Gargantext/Components/Forms.purs
deleted
100644 → 0
View file @
c4060538
module Gargantext.Components.Forms where
import Record as Record
import Reactix as R
import Reactix.DOM.HTML as H
import Gargantext.Utils.Reactix as R2
clearfix :: R.Element
clearfix = H.div { className: "clearfix" } []
formGroup :: Array R.Element -> R.Element
formGroup = H.div { className: "form-group" }
center :: Array R.Element -> R.Element
center = H.div { className: "center" }
card :: Array R.Element -> R.Element
card = H.div { className: "card" }
cardBlock :: Array R.Element -> R.Element
cardBlock = H.div { className: "card-block" }
cardGroup :: Array R.Element -> R.Element
cardGroup = H.div { className: "card-group" }
src/Gargantext/Components/Login.purs
View file @
313c616d
...
@@ -17,7 +17,6 @@ module Gargantext.Components.Login
...
@@ -17,7 +17,6 @@ module Gargantext.Components.Login
import Gargantext.Prelude
import Gargantext.Prelude
import DOM.Simple.Event as DE
import Data.Array (head)
import Data.Array (head)
import Data.Foldable (intercalate)
import Data.Foldable (intercalate)
import Data.Maybe (Maybe(..), fromMaybe)
import Data.Maybe (Maybe(..), fromMaybe)
...
@@ -27,9 +26,9 @@ import Effect (Effect)
...
@@ -27,9 +26,9 @@ import Effect (Effect)
import Effect.Aff (Milliseconds(..), delay, launchAff_)
import Effect.Aff (Milliseconds(..), delay, launchAff_)
import Effect.Class (liftEffect)
import Effect.Class (liftEffect)
import Gargantext.Components.Bootstrap as B
import Gargantext.Components.Bootstrap as B
import Gargantext.Components.Bootstrap.Types (ComponentStatus(..), Elevation(..), ModalSizing(..), Position(..), TooltipPosition(..))
import Gargantext.Components.Bootstrap.Types (ComponentStatus(..), Elevation(..), ModalSizing(..), Position(..), TooltipPosition(..)
, Variant(..)
)
import Gargantext.Components.Login.ForgotPassword (forgotPassword)
import Gargantext.Components.Login.ForgotPassword (forgotPassword)
import Gargantext.Components.Login.Form
(form)
import Gargantext.Components.Login.Form
as Form
import Gargantext.Components.Login.Types (FormType(..))
import Gargantext.Components.Login.Types (FormType(..))
import Gargantext.Components.NgramsTable.Loader as NTL
import Gargantext.Components.NgramsTable.Loader as NTL
import Gargantext.Ends (Backend(..))
import Gargantext.Ends (Backend(..))
...
@@ -40,7 +39,7 @@ import Gargantext.Utils (nbsp, (?))
...
@@ -40,7 +39,7 @@ import Gargantext.Utils (nbsp, (?))
import Gargantext.Utils.Reactix as R2
import Gargantext.Utils.Reactix as R2
import Reactix as R
import Reactix as R
import Reactix.DOM.HTML as H
import Reactix.DOM.HTML as H
import Re
actix.SyntheticEvent as RE
import Re
cord as Record
import Toestand as T
import Toestand as T
here :: R2.Here
here :: R2.Here
...
@@ -88,7 +87,7 @@ loginContainerCpt = here.component "container" cpt where
...
@@ -88,7 +87,7 @@ loginContainerCpt = here.component "container" cpt where
-- | States
-- | States
-- |
-- |
mBackend <- R2.useLive' props.backend
mBackend <- R2.useLive' props.backend
formType <- T.useBox
Login
formType <- T.useBox
Manager
formType' <- T.useLive T.unequal formType
formType' <- T.useLive T.unequal formType
-- | Render
-- | Render
...
@@ -99,10 +98,14 @@ loginContainerCpt = here.component "container" cpt where
...
@@ -99,10 +98,14 @@ loginContainerCpt = here.component "container" cpt where
[]
[]
[
[
case mBackend of
case mBackend of
Nothing -> chooser props
Nothing ->
chooser $
{ formType
} `Record.merge` props
Just backend -> case formType' of
Just backend -> case formType' of
Login ->
Login ->
form
Form.component
{ backend
{ backend
, formType
, formType
, sessions
, sessions
...
@@ -113,13 +116,27 @@ loginContainerCpt = here.component "container" cpt where
...
@@ -113,13 +116,27 @@ loginContainerCpt = here.component "container" cpt where
{ backend
{ backend
, sessions
, sessions
}
}
Manager ->
chooser $
{ formType
} `Record.merge` props
]
]
chooser :: R2.Leaf Props
type ChooserProps =
( formType :: T.Box FormType
| Props
)
chooser :: R2.Leaf ChooserProps
chooser = R2.leaf chooserCpt
chooser = R2.leaf chooserCpt
chooserCpt :: R.Component Props
chooserCpt :: R.Component
Chooser
Props
chooserCpt = here.component "chooser" cpt where
chooserCpt = here.component "chooser" cpt where
cpt { backend, backends, sessions } _ = do
cpt { backend
, backends
, sessions
, formType
} _ = do
-- | States
-- | States
-- |
-- |
sessions' <- T.useLive T.unequal sessions
sessions' <- T.useLive T.unequal sessions
...
@@ -135,15 +152,22 @@ chooserCpt = here.component "chooser" cpt where
...
@@ -135,15 +152,22 @@ chooserCpt = here.component "chooser" cpt where
[
[
H.h6
H.h6
{}
{}
[
[ H.text "Existing places" ]
H.text "Existing places"
,
,
B.tooltipContainer
H.text $ nbsp 1
{ position: TooltipPosition Top
,
, variant: Info
B.span'
, tooltipSlot:
{ className: "font-weight-normal" }
B.span_ "Available soon"
"(click to login)"
, defaultSlot:
]
B.formInput
{ status: Idled
, placeholder: "Search for your institute"
, value: (mempty :: String)
, callback: const R.nothing
, className: "mb-1"
}
}
,
,
H.table
H.table
{ className : "table" }
{ className : "table" }
...
@@ -160,15 +184,15 @@ chooserCpt = here.component "chooser" cpt where
...
@@ -160,15 +184,15 @@ chooserCpt = here.component "chooser" cpt where
]
]
,
,
H.tbody
H.tbody
{}
{} $
(map (renderBackend backend) backends)
backends <#>
renderBackend <<<
{ backendBox: backend
, formTypeBox: formType
, backend: _
}
]
]
,
H.input
{ className: "form-control"
, type:"text"
, placeholder: "Search for your institute"
}
]
]
-- Shown in the chooser
-- Shown in the chooser
...
@@ -298,52 +322,71 @@ renderSessionCpt = here.component "renderSession" cpt where
...
@@ -298,52 +322,71 @@ renderSessionCpt = here.component "renderSession" cpt where
]
]
]
]
type RenderBackendProps =
( backendBox :: T.Box (Maybe Backend)
, formTypeBox :: T.Box FormType
, backend :: Backend
)
renderBackend :: forall b. T.Write b (Maybe Backend) => b -> Backend -> R.Element
renderBackend :: R2.Leaf RenderBackendProps
renderBackend cursor backend@(Backend {name, baseUrl, backendType}) =
renderBackend = R2.leaf renderBackendCpt
H.tr {}
renderBackendCpt :: R.Component RenderBackendProps
[
renderBackendCpt = here.component "renderBackend" cpt where
H.td
cpt { backendBox
{}
, backend: backend@(Backend { name, baseUrl, backendType })
[
, formTypeBox
B.icon
} _ = do
{ name: "hand-o-right"
-- | Behaviors
}
-- |
]
let
,
click :: Unit -> Effect Unit
H.td
click _ = do
{}
T.write_ (Just backend) backendBox
[
T.write_ (Login) formTypeBox
H.a
{ on: { click }
-- | Render
, className: "text-primary"
-- |
}
pure $
[ H.text (backendLabel name) ]
]
H.tr {}
,
H.td
{}
[
B.span_
backendType
]
,
H.td
{}
[
B.wad
[ "font-family-monospace", "font-size-95" ]
[
[
H.text $ DST.replace (DST.Pattern "http") (DST.Replacement "garg") $ baseUrl
H.td
{}
[
B.icon
{ name: "hand-o-right"
}
]
,
H.td
{}
[
H.a
{ on: { click }
, className: "text-primary"
}
[ H.text (backendLabel name) ]
]
,
H.td
{}
[
B.span_
backendType
]
,
H.td
{}
[
B.wad
[ "font-family-monospace", "font-size-95" ]
[
H.text $ DST.replace (DST.Pattern "http") (DST.Replacement "garg") $ baseUrl
]
]
]
]
]
]
where
click :: RE.SyntheticEvent DE.Event -> Effect Unit
click e = do
RE.preventDefault e
T.write_ (Just backend) cursor
backendLabel :: String -> String
backendLabel :: String -> String
backendLabel =
backendLabel =
...
...
src/Gargantext/Components/Login/ForgotPassword.purs
View file @
313c616d
...
@@ -8,7 +8,6 @@ import Effect (Effect)
...
@@ -8,7 +8,6 @@ import Effect (Effect)
import Effect.Aff (launchAff_)
import Effect.Aff (launchAff_)
import Effect.Class (liftEffect)
import Effect.Class (liftEffect)
import Formula as F
import Formula as F
import Gargantext.Components.Forms (formGroup)
import Gargantext.Ends (Backend)
import Gargantext.Ends (Backend)
import Gargantext.Sessions (Sessions, postForgotPasswordRequest)
import Gargantext.Sessions (Sessions, postForgotPasswordRequest)
import Gargantext.Utils.Reactix as R2
import Gargantext.Utils.Reactix as R2
...
@@ -34,12 +33,12 @@ forgotPasswordCpt = here.component "forgotPassword" cpt where
...
@@ -34,12 +33,12 @@ forgotPasswordCpt = here.component "forgotPassword" cpt where
email <- T.useBox ""
email <- T.useBox ""
message <- T.useBox ""
message <- T.useBox ""
disabled <- T.useBox false
disabled <- T.useBox false
pure $ H.div { className: "row" }
pure $ H.div { className: "row" }
[ H.form { className: "text-center col-md-12" }
[ H.form { className: "text-center col-md-12" }
[ H.h4 {} [ H.text "Forgot password" ]
[ H.h4 {} [ H.text "Forgot password" ]
, messageDisplay { message }
, messageDisplay { message }
,
formGroup
,
H.div { className: "form-group" }
[ emailInput { email, disabled} ]
[ emailInput { email, disabled} ]
, submitButton { backend, email, sessions, message, disabled }
, submitButton { backend, email, sessions, message, disabled }
]
]
...
@@ -51,7 +50,7 @@ emailInput = R2.leaf emailInputCpt
...
@@ -51,7 +50,7 @@ emailInput = R2.leaf emailInputCpt
emailInputCpt :: R.Component (email :: T.Box Email, disabled :: T.Box Boolean)
emailInputCpt :: R.Component (email :: T.Box Email, disabled :: T.Box Boolean)
emailInputCpt = here.component "emailInput" cpt where
emailInputCpt = here.component "emailInput" cpt where
cpt { email, disabled } _ = do
cpt { email, disabled } _ = do
disabled' <- T.useLive T.unequal disabled
disabled' <- T.useLive T.unequal disabled
pure $ F.bindInput { value: email
pure $ F.bindInput { value: email
, type: "email"
, type: "email"
, className: "form-control"
, className: "form-control"
...
@@ -74,8 +73,8 @@ submitButtonCpt = here.component "submitButton" cpt where
...
@@ -74,8 +73,8 @@ submitButtonCpt = here.component "submitButton" cpt where
cpt { backend, email, sessions, message, disabled} _ = do
cpt { backend, email, sessions, message, disabled} _ = do
email' <- T.useLive T.unequal email
email' <- T.useLive T.unequal email
disabled' <- T.useLive T.unequal disabled
disabled' <- T.useLive T.unequal disabled
pure $ H.div {className: "form-group text-center"}
pure $ H.div {className: "form-group text-center"}
[ H.button { className: "btn btn-primary"
[ H.button { className: "btn btn-primary"
, disabled: disabled'
, disabled: disabled'
, on: { click: click email' }}
, on: { click: click email' }}
...
@@ -106,4 +105,4 @@ messageDisplayCpt = here.component "messageDisplay" cpt where
...
@@ -106,4 +105,4 @@ messageDisplayCpt = here.component "messageDisplay" cpt where
cpt {message} _ = do
cpt {message} _ = do
message' <- T.useLive T.unequal message
message' <- T.useLive T.unequal message
pure $ H.p {} [H.text message']
pure $ H.p {} [H.text message']
\ No newline at end of file
src/Gargantext/Components/Login/Form.purs
View file @
313c616d
module Gargantext.Components.Login.Form where
module Gargantext.Components.Login.Form
( component
) where
import Gargantext.Prelude
import Prelude (Unit, bind, discard, not, notEq, pure, show, unit, ($), (&&), (*>), (<>))
import Data.Either (Either(..))
import Data.Either (Either(..))
import DOM.Simple.Event as DE
import Data.Foldable (foldl, intercalate)
import Data.Maybe (Maybe(..))
import Data.String as String
import Data.Tuple.Nested ((/\))
import Effect (Effect)
import Effect (Effect)
import Effect.Aff (launchAff_)
import Effect.Aff (
Aff,
launchAff_)
import Effect.Class (liftEffect)
import Effect.Class (liftEffect)
import Formula as F
import Gargantext.Components.Bootstrap as B
import Reactix as R
import Gargantext.Components.Bootstrap.Types (ButtonVariant(..), ComponentStatus(..), Elevation(..), Sizing(..), Variant(..))
import Reactix.SyntheticEvent as E
import Reactix.DOM.HTML as H
import Toestand as T
import Toestand (useFocusedFields)
import Data.String as String
import Gargantext.Components.Forms (clearfix, formGroup)
import Gargantext.Components.Login.Types (AuthRequest(..), FormType(..))
import Gargantext.Components.Login.Types (AuthRequest(..), FormType(..))
import Gargantext.Ends (Backend)
import Gargantext.Ends (Backend)
import Gargantext.Hooks.FormValidation (VForm, useFormValidation)
import Gargantext.Hooks.FormValidation.Unboxed as FV
import Gargantext.Hooks.StateRecord (useStateRecord)
import Gargantext.Sessions (Session, Sessions, postAuthRequest)
import Gargantext.Sessions as Sessions
import Gargantext.Sessions as Sessions
import Gargantext.Sessions (Sessions, postAuthRequest)
import Gargantext.Utils ((?))
import Gargantext.Utils (csrfMiddlewareToken)
import Gargantext.Utils.Reactix as R2
import Gargantext.Utils.Reactix as R2
import Reactix as R
import Reactix.DOM.HTML as H
import Record as Record
import Toestand as T
here :: R2.Here
here :: R2.Here
here = R2.here "Gargantext.Components.Login.Form"
here = R2.here "Gargantext.Components.Login.Form"
type
Form
=
type
Props
=
{ error :: String
( backend :: Backend
,
username :: String
,
formType :: T.Box FormType
,
password :: String
,
sessions :: T.Box Sessions
,
agreed ::
Boolean
,
visible :: T.Box
Boolean
}
)
emptyForm :: Form
component :: R2.Leaf Props
emptyForm = { error: "", username: "", password: "", agreed: false }
component = R2.leaf componentCpt
componentCpt :: R.Component Props
componentCpt = here.component "main" cpt where
cpt { backend
, formType
, sessions
, visible
} _ = do
-- | States
-- |
error' /\ error
<- R2.useBox' (Nothing :: Maybe String)
type Boxes =
onPending' /\ onPending
{ error :: T.Box String
<- R2.useBox' false
, username :: T.Box String
, password :: T.Box String
, agreed :: T.Box Boolean }
formBoxes :: T.Box Form -> R.Hooks Boxes
-- | Hooks
formBoxes box = useFocusedFields box {}
-- |
{ state, bindStateKey } <- useStateRecord (defaultData :: FormData)
fv <- useFormValidation
type Props s v =
-- | Behaviors
( backend :: Backend
-- |
, formType :: T.Box FormType
let
, sessions :: s
onReturnClick :: Unit -> Effect Unit
, visible :: v
onReturnClick _ = T.write_ (Manager) formType
)
form :: forall s v. T.ReadWrite s Sessions => T.ReadWrite v Boolean
onPasswordForgottenClick :: Unit -> Effect Unit
=> Record (Props s v) -> R.Element
onPasswordForgottenClick _ = T.write_ (ForgotPassword) formType
form props = R.createElement formCpt props []
formCpt :: forall s v. T.ReadWrite s Sessions => T.ReadWrite v Boolean
=> R.Component (Props s v)
formCpt = here.component "form" cpt where
cpt { backend, formType, sessions, visible } _ = do
cell <- T.useBox emptyForm
cursors <- useFocusedFields cell {}
pure $ R2.row
[ H.form { className: "col-md-12" }
[ formLoginLink backend
, requestAccessLink
, csrfTokenInput
, formGroup
[ H.p {} [ F.viewText { text: cursors.error } ]
, usernameInput cursors.username ]
, formGroup
[ passwordInput cursors.password
, clearfix ]
, termsCheckbox cursors.agreed
, submitButton { backend, formType, sessions, visible, cell }
, forgotPassword { formType }
]]
-- might be wrong, all we care about is preventDefault
type ChangeEvent = R.SyntheticEvent DE.MouseEvent
formLoginLink :: Backend -> R.Element
formLoginLink backend =
H.h4 { className: "text-center" } {-className: "text-muted"-}
[ H.text $ "Login to garg://" <> show backend ]
type SubmitButtonProps s v = ( cell :: T.Box Form | Props s v )
submitButton :: forall s v. T.ReadWrite s Sessions => T.Write v Boolean
=> R2.Leaf (SubmitButtonProps s v)
submitButton = R2.leafComponent submitButtonCpt
submitButtonCpt :: forall s v. T.ReadWrite s Sessions => T.Write v Boolean
=> R.Component (SubmitButtonProps s v)
submitButtonCpt = here.component "submitButton" cpt where
cpt { backend, formType, sessions, visible, cell } _ = do
{ agreed, username, password } <- T.useLive T.unequal cell
let isValid = agreed && (username `notEq` "") && (password `notEq` "")
pure $ H.div { className: "text-center" }
[ loginSubmit isValid $ submitForm { backend, formType, sessions, visible } cell ]
-- Attempts to submit the form
submitForm :: forall s v. T.ReadWrite s Sessions => T.Write v Boolean
=> Record (Props s v) -> T.Box Form -> ChangeEvent -> Effect Unit
submitForm { backend, sessions, visible } cell e = do
E.preventDefault e
state <- T.read cell
launchAff_ $ do
res <- postAuthRequest backend (req state)
_ <- case res of
Left message -> liftEffect $ T.write (state { error = message }) cell
Right sess ->
liftEffect $
Sessions.change (Sessions.Login sess) sessions
*> T.write false visible
*> T.write (state { error = "" }) cell
pure unit
where
-- User usually copy space before or after the username and password
req { username, password } = AuthRequest {username:cleanString username, password:cleanString password }
-- req { username, password } = AuthRequest {username, password }
cleanString :: String -> String
onSubmit :: Unit -> Effect Unit
cleanString str = String.replace (String.Pattern " ")
onSubmit _ = do
(String.Replacement "") str
result <- fv.try (\_ -> formValidation state)
csrfTokenInput :: R.Element -- TODO hard-coded CSRF token
case result of
csrfTokenInput = H.input { type: "hidden", name, value } where
name = "csrfmiddlewaretoken"
Left err -> here.log3 "validation error" state err
value = csrfMiddlewareToken
Right _ -> do
termsCheckbox :: forall cell. T.ReadWrite cell Boolean => cell -> R.Element
T.write_ true onPending
termsCheckbox checked =
launchAff_
H.div { className: "form-group form-check text-center" }
$ signin backend state
[ F.bindCheckbox { checked, className: "form-check-input" }
>>= case _ of
, H.label { className: "form-check-label" }
[ H.text "I hereby accept the "
Left err -> liftEffect
, H.a { target: "_blank", href: termsUrl }
$ here.warn3 "request error" state err
[ H.text "terms of use" ] ]]
*> T.write_ (Just err) error
where termsUrl = "http://gitlab.iscpif.fr/humanities/tofu/tree/master"
Right session_ -> liftEffect
requestAccessLink :: R.Element
$ Sessions.change (Sessions.Login session_) sessions
requestAccessLink =
*> T.write_ false visible
H.div { className: "text-center" }
[ H.a { href, target: "_blank" } [ H.text "request access" ] ]
T.write_ false onPending
where href = "https://iscpif.fr/apply-for-a-services-account/"
-- | Render
usernameInput :: forall cell. T.ReadWrite cell String => cell -> R.Element
-- |
usernameInput value =
pure $
F.bindInput
{ value
H.div
, type: "text", className: "form-control"
{ className: "login-modal-form" }
, id: "id_username", placeholder: "username"
[
, name: "username", maxLength: "254"
H.div
{ className: "login-modal-form__title" }
[
B.iconButton
{ name: "arrow-left"
, className: "login-modal-form__title__return"
, elevation: Level2
, callback: onReturnClick
}
,
H.span
{ className: "login-modal-form__title__text" }
[
H.text $ "garg://" <> show backend
]
]
,
H.a
{ href: "https://iscpif.fr/apply-for-a-services-account/"
, target: "_blank"
, className: intercalate " "
[ "login-modal-form__request-access"
, "btn btn-primary"
]
}
[
B.icon
{ name: "hand-o-right" }
,
B.wad_
[ "d-inline-block", "virtual-space", "w-1" ]
,
H.text "Request access"
]
,
H.div
{ className: "login-modal-form__separator" }
[
H.hr
{}
,
H.span
{ className: "login-modal-form__separator__text" }
[ H.text "or" ]
]
,
H.form
{ className: "login-modal-form__form" }
[
-- (?) never used?
-- H.input
-- { type: "hidden"
-- , name: "csrfmiddlewaretoken"
-- , value: csrfMiddlewareToken
-- }
-- Username
H.div
{ className: intercalate " "
[ "form-group"
, (fv.hasError' "username") ?
"form-group--error" $
mempty
]
}
[
H.div { className: "form-group__label" }
[
H.label {} [ H.text "Username" ]
]
,
H.div { className: "form-group__field" }
[
B.formInput $
{ size: LargeSize
} `Record.merge` bindStateKey "username"
]
]
,
-- Password
H.div
{ className: intercalate " "
[ "form-group"
, (fv.hasError' "password") ?
"form-group--error" $
mempty
]
}
[
H.div { className: "form-group__label" }
[
H.label {} [ H.text "Password" ]
]
,
H.div { className: "form-group__field" }
[
B.formInput $
{ size: LargeSize
, type: "password"
} `Record.merge` bindStateKey "password"
,
H.a
{ on: { click: onPasswordForgottenClick }
, className: "font-size-95 text-decoration-underline"
}
[ H.text "Password forgotten" ]
]
]
,
-- Error
R2.fromMaybe error' $
B.div'
{ className: "login-modal-form__error" }
,
-- Submit
B.button
{ callback: onSubmit
, status: onPending' ? Deferred $ Enabled
, variant: ButtonVariant Primary
, type: "submit"
, className: "login-modal-form__log-in"
}
[
B.icon
{ name: "hand-o-right" }
,
B.wad_
[ "d-inline-block", "virtual-space", "w-1" ]
,
H.text "Log in"
]
]
]
-- R2.row
-- [
-- H.form
-- { className: "col-md-12" }
-- [
-- H.h4
-- { className: "text-center" }
-- [ H.text $ "Login to garg://" <> show backend ]
-- ,
-- H.div
-- { className: "text-center" }
-- [
-- H.a
-- { href: "https://iscpif.fr/apply-for-a-services-account/"
-- , target: "_blank"
-- }
-- [ H.text "request access" ]
-- ]
-- ,
-- H.div
-- { className: "form-group form-check text-center" }
-- [
-- F.bindCheckbox
-- { checked: cursors.agreed
-- , className: "form-check-input"
-- }
-- ,
-- H.label
-- { className: "form-check-label" }
-- [
-- H.text "I hereby accept the "
-- ,
-- H.a
-- { target: "_blank"
-- , href: "http://gitlab.iscpif.fr/humanities/tofu/tree/master"
-- }
-- [ H.text "terms of use" ]
-- ]
-- ]
-- H.div
-- {}
-- [
-- H.a
-- { on: { click: \_ -> T.write_ ForgotPassword formType
-- }
-- }
-- [ H.text "Forgot password?" ]
-- ]
-- ]
-- ]
type FormData =
{ error :: String
, username :: String
, password :: String
, agreed :: Boolean
}
}
passwordInput :: forall cell. T.ReadWrite cell String => cell -> R.Element
defaultData :: FormData
passwordInput value =
defaultData =
F.bindInput
{ error : ""
{ value
, username : ""
, type: "password", className: "form-control"
, password : ""
, name: "password", placeholder: "password"
, agreed : false
, id: "id_password"
}
}
loginSubmit :: Boolean -> (ChangeEvent -> Effect Unit) -> R.Element
formValidation :: FormData -> Effect VForm
loginSubmit isEnabled click =
formValidation r = foldl append mempty rules
H.button { id
where
, className
rules =
, disabled: not isEnabled
[ FV.nonEmpty "username" r.username
, type: "submit"
, FV.nonEmpty "password" r.password
, on: { click } }
, FV.equals "agreed" false r.agreed
[ H.text "Login" ] where
id = "login-button"
className = "btn btn-primary btn-rounded"
type ForgotPasswordProps =
( formType :: T.Box FormType )
forgotPassword :: R2.Leaf ForgotPasswordProps
forgotPassword = R2.leaf forgotPasswordCpt
forgotPasswordCpt :: R.Component ForgotPasswordProps
forgotPasswordCpt = here.component "forgotPassword" cpt where
cpt { formType } _ = do
pure $ H.div { className: "" }
[ H.a { className: "",
on: { click } } [ H.text "Forgot password?" ]
]
]
where
click _ = T.write_ ForgotPassword formType
-----------------------------------------------
signin ::
Backend
-> FormData
-> Aff (Either String Session)
signin backend { username, password } = postAuthRequest backend request
where
-- (?) is `cleanString` necessary?
request
= AuthRequest { username: cleanString username
, password: cleanString password
}
cleanString :: String -> String
cleanString str =
String.replace (String.Pattern " ")
(String.Replacement "") str
src/Gargantext/Components/Login/Types.purs
View file @
313c616d
...
@@ -55,6 +55,6 @@ instance Eq AuthData where
...
@@ -55,6 +55,6 @@ instance Eq AuthData where
_AuthData :: Iso' AuthData { token :: Token, tree_id :: TreeId, user_id :: UserId }
_AuthData :: Iso' AuthData { token :: Token, tree_id :: TreeId, user_id :: UserId }
_AuthData = iso (\(AuthData v) -> v) AuthData
_AuthData = iso (\(AuthData v) -> v) AuthData
data FormType = Login | ForgotPassword
data FormType = Login | ForgotPassword
| Manager
derive instance Generic FormType _
derive instance Generic FormType _
derive instance Eq FormType
derive instance Eq FormType
src/Gargantext/Hooks/FormValidation/Boxed.purs
View file @
313c616d
...
@@ -61,6 +61,17 @@ instance maximumString :: Maximum String where
...
@@ -61,6 +61,17 @@ instance maximumString :: Maximum String where
| (length input) > max -> pure $ invalid [ field /\ "maximum" ]
| (length input) > max -> pure $ invalid [ field /\ "maximum" ]
| otherwise -> pure $ pure unit
| otherwise -> pure $ pure unit
-- Regarding Boolean field value
instance equalsBoolean :: Equals Boolean where
equals field box box' = do
input <- T.read box
input' <- T.read box'
case unit of
_
| (not eq input input') -> pure $ invalid [ field /\ "equals" ]
| otherwise -> pure $ pure unit
uppercase :: Field -> T.Box String -> Effect VForm
uppercase :: Field -> T.Box String -> Effect VForm
uppercase field = T.read >=> case _ of
uppercase field = T.read >=> case _ of
input
input
...
...
src/Gargantext/Hooks/FormValidation/Unboxed.purs
View file @
313c616d
...
@@ -52,6 +52,13 @@ instance maximumString :: Maximum String where
...
@@ -52,6 +52,13 @@ instance maximumString :: Maximum String where
| (length input) > max = pure $ invalid [ field /\ "maximum" ]
| (length input) > max = pure $ invalid [ field /\ "maximum" ]
| otherwise = pure $ pure unit
| otherwise = pure $ pure unit
-- Regarding Boolean field value
instance equalsBoolean :: Equals Boolean where
equals field input input'
| (not eq input input') = pure $ invalid [ field /\ "equals" ]
| otherwise = pure $ pure unit
uppercase :: Field -> String -> Effect VForm
uppercase :: Field -> String -> Effect VForm
uppercase field input
uppercase field input
| (toLower input) == input = pure $ invalid [ field /\ "uppercase" ]
| (toLower input) == input = pure $ invalid [ field /\ "uppercase" ]
...
...
src/sass/_legacy/_login.sass
View file @
313c616d
...
@@ -9,3 +9,71 @@
...
@@ -9,3 +9,71 @@
&
__actions
&
__actions
display
:
flex
display
:
flex
gap
:
space-x
(
3
.5
)
gap
:
space-x
(
3
.5
)
//////////////////////////////////:
.login-modal-form
$cta-width
:
200px
$form-width
:
520px
&
__title
position
:
relative
background-color
:
$border-color
padding
:
$card-spacer-y
$card-spacer-x
text-align
:
center
// (?) dirty negative margins to overlap the ".modal-body" paddings
margin-top
:
-
$modal-inner-padding
margin-left
:
-
$modal-inner-padding
margin-right
:
-
$modal-inner-padding
&
__return
@include
centered
position
:
absolute
left
:
space-x
(
3
.5
)
&
__text
font-family
:
$font-family-monospace
font-size
:
20px
font-weight
:
bold
&
__separator
padding
:
$card-spacer-y
calc
(
2
*
#{
$card-spacer-x
}
)
position
:
relative
&
__text
@include
centered
position
:
absolute
display
:
inline-block
padding-left
:
space-x
(
4
)
padding-right
:
space-x
(
4
)
font-family
:
$headings-font-family
font-size
:
24px
background-color
:
$modal-content-bg
&
__request-access
margin-top
:
calc
(
3
*
#{
$card-spacer-y
}
)
margin-left
:
auto
margin-right
:
auto
margin-bottom
:
$card-spacer-y
padding
:
$btn-padding-y-lg
$btn-padding-x-lg
width
:
$cta-width
display
:
block
&
__log-in
padding
:
$btn-padding-y-lg
$btn-padding-x-lg
width
:
$cta-width
margin-bottom
:
calc
(
2
*
#{
$card-spacer-y
}
)
margin-left
:
auto
margin-right
:
auto
margin-top
:
$card-spacer-y
display
:
block
&
__form
margin
:
0
auto
width
:
$form-width
&
__error
margin-bottom
:
$form-group-margin-bottom
color
:
$danger
text-align
:
center
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment