Navigation bar now has a dedicated component.

beta
Philippe Pittoli 2024-02-22 05:42:25 +01:00
parent 88b1221569
commit 6c4ed85335
4 changed files with 159 additions and 43 deletions

View File

@ -49,8 +49,6 @@ import Prelude (Unit, bind, discard, unit, ($), (=<<), (<>), show, pure)
import Bulma as Bulma import Bulma as Bulma
import App.Nav as Nav
import Data.Array as A import Data.Array as A
import Data.Maybe (Maybe(..), maybe) import Data.Maybe (Maybe(..), maybe)
import Data.Either (Either(..)) import Data.Either (Either(..))
@ -64,6 +62,7 @@ import App.AdministrationInterface as AdminI
import App.DomainListInterface as DomainListInterface import App.DomainListInterface as DomainListInterface
import App.ZoneInterface as ZoneInterface import App.ZoneInterface as ZoneInterface
import App.HomeInterface as HomeInterface import App.HomeInterface as HomeInterface
import App.NavigationInterface as NavigationInterface
import App.Messages.DNSManagerDaemon as DNSManager import App.Messages.DNSManagerDaemon as DNSManager
import App.Messages.AuthenticationDaemon as AuthD import App.Messages.AuthenticationDaemon as AuthD
import Halogen as H import Halogen as H
@ -78,17 +77,7 @@ import Web.Storage.Storage as Storage
import App.LogMessage (LogMessage(..)) import App.LogMessage (LogMessage(..))
-- | This list will grow in a near future. import App.Pages
-- |
-- | TODO:
data Page
= Home -- | `Home`: presentation of the project.
| Authentication -- | `Authentication`: authentication page.
| Registration -- | `Registration`: to register new people.
| MailValidation -- | `MailValidation`: to validate email addresses (via a token).
| DomainList -- | `DomainList`: to list owned domains and to ask for new domains.
| Zone String -- | `Zone`: to manage a zone.
| Administration -- | `Administration`: administration page (for both `authd` and `dnsmanagerd`).
type Token = String type Token = String
type Login = String type Login = String
@ -105,6 +94,9 @@ data Action
-- | Handle events from `MailValidationInterface`. -- | Handle events from `MailValidationInterface`.
| MailValidationInterfaceEvent MVI.Output | MailValidationInterfaceEvent MVI.Output
-- | Handle events from `NavigationInterface`.
| NavigationInterfaceEvent NavigationInterface.Output
-- | Handle events from `AuthenticationDaemonAdminComponent`. -- | Handle events from `AuthenticationDaemonAdminComponent`.
| AdministrationEvent AdminI.Output -- Administration interface. | AdministrationEvent AdminI.Output -- Administration interface.
@ -155,6 +147,10 @@ data Action
-- | `KeepAlive` send a keepalive message to either `authd` or `dnsmanagerd`. -- | `KeepAlive` send a keepalive message to either `authd` or `dnsmanagerd`.
| KeepAlive (Either Unit Unit) | KeepAlive (Either Unit Unit)
-- | `ToggleAuthenticated` performs some actions required when a connection or a disconnection occurs.
-- | Currently, this handles the navigation bar.
| ToggleAuthenticated (Maybe Token)
-- | The component's state is composed of: -- | The component's state is composed of:
-- | a potential authentication token, -- | a potential authentication token,
-- | the current page, -- | the current page,
@ -174,6 +170,7 @@ type ChildSlots =
, ho :: HomeInterface.Slot Unit , ho :: HomeInterface.Slot Unit
, ws_auth :: WS.Slot Unit , ws_auth :: WS.Slot Unit
, ws_dns :: WS.Slot Unit , ws_dns :: WS.Slot Unit
, nav :: NavigationInterface.Slot Unit
, ai :: AI.Slot Unit , ai :: AI.Slot Unit
, ri :: RI.Slot Unit , ri :: RI.Slot Unit
, mvi :: MVI.Slot Unit , mvi :: MVI.Slot Unit
@ -186,6 +183,7 @@ _ho = Proxy :: Proxy "ho" -- Home Interface
_log = Proxy :: Proxy "log" -- Log _log = Proxy :: Proxy "log" -- Log
_ws_auth = Proxy :: Proxy "ws_auth" -- WS with `authd` _ws_auth = Proxy :: Proxy "ws_auth" -- WS with `authd`
_ws_dns = Proxy :: Proxy "ws_dns" -- WS with `dnsmanagerd` _ws_dns = Proxy :: Proxy "ws_dns" -- WS with `dnsmanagerd`
_nav = Proxy :: Proxy "nav" -- Navigation Interface
_ai = Proxy :: Proxy "ai" -- Authentication Interface _ai = Proxy :: Proxy "ai" -- Authentication Interface
_ri = Proxy :: Proxy "ri" -- Registration Interface _ri = Proxy :: Proxy "ri" -- Registration Interface
_mvi = Proxy :: Proxy "mvi" -- Mail Validation Interface _mvi = Proxy :: Proxy "mvi" -- Mail Validation Interface
@ -243,27 +241,13 @@ render state
render_authd_admin_interface :: forall monad. MonadAff monad => H.ComponentHTML Action ChildSlots monad render_authd_admin_interface :: forall monad. MonadAff monad => H.ComponentHTML Action ChildSlots monad
render_authd_admin_interface = HH.slot _admini unit AdminI.component unit AdministrationEvent render_authd_admin_interface = HH.slot _admini unit AdminI.component unit AdministrationEvent
authenticated = case state.token of
Nothing -> false
Just _ -> true
-- TODO: this is needed to show the authd admin button
admin = true
render_nav :: forall monad. MonadAff monad => H.ComponentHTML Action ChildSlots monad render_nav :: forall monad. MonadAff monad => H.ComponentHTML Action ChildSlots monad
render_nav = Nav.netlibre_navbar authenticated admin render_nav = HH.slot _nav unit NavigationInterface.component unit NavigationInterfaceEvent
(Routing Home)
(Routing DomainList)
(Routing Administration)
(Routing Authentication)
(Routing Registration)
(Routing MailValidation)
Disconnection
render_header :: forall monad. MonadAff monad => H.ComponentHTML Action ChildSlots monad render_header :: forall monad. MonadAff monad => H.ComponentHTML Action ChildSlots monad
render_header = case state.token of render_header = case state.token of
Nothing -> Bulma.hero "net libre" "free domains" Nothing -> Bulma.hero "net libre" "free domains"
Just _ -> Bulma.hero "net libre" "free domains" Just _ -> Bulma.hero "net libre" ""
render_logs :: forall monad. MonadAff monad => H.ComponentHTML Action ChildSlots monad render_logs :: forall monad. MonadAff monad => H.ComponentHTML Action ChildSlots monad
render_logs = Bulma.container [ HH.slot_ _log unit AppLog.component unit ] render_logs = Bulma.container [ HH.slot_ _log unit AppLog.component unit ]
@ -292,6 +276,10 @@ handleAction = case _ of
Log message -> H.tell _log unit $ AppLog.Log message Log message -> H.tell _log unit $ AppLog.Log message
ToggleAuthenticated maybe_token -> case maybe_token of
Nothing -> H.tell _nav unit $ NavigationInterface.ToggleLogged false
Just _ -> H.tell _nav unit $ NavigationInterface.ToggleLogged true
KeepAlive auth_or_dnsmanager -> case auth_or_dnsmanager of KeepAlive auth_or_dnsmanager -> case auth_or_dnsmanager of
Left _ -> do Left _ -> do
message <- H.liftEffect $ AuthD.serialize $ AuthD.MkKeepAlive {} message <- H.liftEffect $ AuthD.serialize $ AuthD.MkKeepAlive {}
@ -324,6 +312,11 @@ handleAction = case _ of
H.modify_ _ { token = Just t } H.modify_ _ { token = Just t }
handleAction AuthenticateToDNSManager handleAction AuthenticateToDNSManager
NavigationInterfaceEvent ev -> case ev of
NavigationInterface.Log message -> H.tell _log unit (AppLog.Log message)
NavigationInterface.Routing page -> handleAction $ Routing page
NavigationInterface.Disconnection -> handleAction $ Disconnection
AuthenticationInterfaceEvent ev -> case ev of AuthenticationInterfaceEvent ev -> case ev of
AI.MessageToSend message -> H.tell _ws_auth unit (WS.ToSend message) AI.MessageToSend message -> H.tell _ws_auth unit (WS.ToSend message)
AI.AuthenticateToAuthd v -> handleAction $ AuthenticateToAuthd (Right v) AI.AuthenticateToAuthd v -> handleAction $ AuthenticateToAuthd (Right v)
@ -457,6 +450,7 @@ handleAction = case _ of
handleAction $ Log $ ErrorLog "Email required!" handleAction $ Log $ ErrorLog "Email required!"
(AuthD.GotErrorInvalidCredentials _) -> do (AuthD.GotErrorInvalidCredentials _) -> do
handleAction $ Log $ ErrorLog "Invalid credentials!" handleAction $ Log $ ErrorLog "Invalid credentials!"
handleAction $ ToggleAuthenticated Nothing
(AuthD.GotErrorRegistrationsClosed _) -> do (AuthD.GotErrorRegistrationsClosed _) -> do
handleAction $ Log $ ErrorLog "Registration closed! Try another time or contact an administrator." handleAction $ Log $ ErrorLog "Registration closed! Try another time or contact an administrator."
(AuthD.GotErrorInvalidLoginFormat _) -> do (AuthD.GotErrorInvalidLoginFormat _) -> do
@ -479,6 +473,7 @@ handleAction = case _ of
(AuthD.GotToken msg) -> do (AuthD.GotToken msg) -> do
handleAction $ Log $ SuccessLog $ "Authenticated to authd!" handleAction $ Log $ SuccessLog $ "Authenticated to authd!"
H.modify_ _ { token = Just msg.token } H.modify_ _ { token = Just msg.token }
handleAction $ ToggleAuthenticated (Just msg.token)
sessionstorage <- H.liftEffect $ Window.sessionStorage =<< HTML.window sessionstorage <- H.liftEffect $ Window.sessionStorage =<< HTML.window
_ <- H.liftEffect $ Storage.setItem "user-authd-token" msg.token sessionstorage _ <- H.liftEffect $ Storage.setItem "user-authd-token" msg.token sessionstorage
@ -561,6 +556,8 @@ handleAction = case _ of
(DNSManager.MkErrorInvalidToken _) -> do (DNSManager.MkErrorInvalidToken _) -> do
H.modify_ _ { token = Nothing, current_page = Home } H.modify_ _ { token = Nothing, current_page = Home }
handleAction $ Log $ ErrorLog $ "Invalid token! Try re-authenticate." handleAction $ Log $ ErrorLog $ "Invalid token! Try re-authenticate."
-- TODO: should we disconnect from authd?
handleAction $ ToggleAuthenticated Nothing
(DNSManager.MkDomainAlreadyExists _) -> do (DNSManager.MkDomainAlreadyExists _) -> do
handleAction $ Log $ ErrorLog $ "The domain already exists." handleAction $ Log $ ErrorLog $ "The domain already exists."
m@(DNSManager.MkUnacceptableDomain _) -> do m@(DNSManager.MkUnacceptableDomain _) -> do

View File

@ -32,13 +32,6 @@ netlibre_navbar authenticated admin
false, _ -> [ link_home ] false, _ -> [ link_home ]
_, false -> [ link_home, link_domains ] _, false -> [ link_home, link_domains ]
_, _ -> [ link_home, link_domains, link_authd_admin ] _, _ -> [ link_home, link_domains, link_authd_admin ]
--, dropdown "List of something"
-- [ dropdown_element "something 1"
-- , dropdown_element "something 2"
-- , dropdown_element "something 3"
-- , dropdown_separator
-- , dropdown_element "something 4"
-- ]
] ]
, navbar_end , navbar_end
[ navbar_item [ navbar_item
@ -58,7 +51,15 @@ netlibre_navbar authenticated admin
logo = HH.a [HP.classes C.navbar_item, HP.href "/"] [HH.img [HP.src "/logo.jpeg", HP.width 112, HP.height 28]] logo = HH.a [HP.classes C.navbar_item, HP.href "/"] [HH.img [HP.src "/logo.jpeg", HP.width 112, HP.height 28]]
burger_menu burger_menu
= HH.a [HP.classes C.navbar_burger, ARIA.label "menu", ARIA.expanded "false", Bulma.data_target "navbarExample" ] = HH.a [HP.classes C.navbar_burger, ARIA.label "menu", ARIA.expanded "false", Bulma.data_target "navbarExample" ]
[ HH.span [ARIA.hidden "true"] [] [ HH.span [ARIA.hidden "true"] [
dropdown "List of something"
[ dropdown_element "something 1"
, dropdown_element "something 2"
, dropdown_element "something 3"
, dropdown_separator
, dropdown_element "something 4"
]
]
, HH.span [ARIA.hidden "true"] [] , HH.span [ARIA.hidden "true"] []
, HH.span [ARIA.hidden "true"] [] , HH.span [ARIA.hidden "true"] []
] ]
@ -70,12 +71,14 @@ netlibre_navbar authenticated admin
link_domains = nav_button C.is_info "Domains" actionDomainList link_domains = nav_button C.is_info "Domains" actionDomainList
link_authd_admin = nav_button C.is_info "Admin" actionAdmin link_authd_admin = nav_button C.is_info "Admin" actionAdmin
nav_button_disconnection = nav_button C.is_danger "Disconnection" actionDisconnection nav_button_disconnection = nav_button C.is_danger "Disconnection" actionDisconnection
--dropdown title dropdown_elements
-- = HH.div [HP.classes (C.navbar_item <> C.has_dropdown <> C.is_hoverable)] dropdown title dropdown_elements
-- [ dropdown_title title, HH.div [HP.classes C.navbar_dropdown] dropdown_elements ] = HH.div [HP.classes (C.navbar_item <> C.has_dropdown <> C.is_hoverable)]
--dropdown_title str = HH.a [HP.classes C.navbar_link] [HH.text str] [ dropdown_title title, HH.div [HP.classes C.navbar_dropdown] dropdown_elements ]
--dropdown_element str = HH.a [HP.classes C.navbar_item] [HH.text str] dropdown_title str = HH.a [HP.classes C.navbar_link] [HH.text str]
--dropdown_separator = HH.hr [HP.classes C.navbar_divider] dropdown_element str = HH.a [HP.classes C.navbar_item] [HH.text str]
dropdown_separator = HH.hr [HP.classes C.navbar_divider]
nav_button_code = btn_link [] "https://git.baguette.netlib.re/Baguette/dnsmanager" "Code" nav_button_code = btn_link [] "https://git.baguette.netlib.re/Baguette/dnsmanager" "Code"
nav_button_strong str action = btn C.is_primary action (HH.strong [] [ HH.text str ]) nav_button_strong str action = btn C.is_primary action (HH.strong [] [ HH.text str ])
nav_button classes str action = btn classes action (HH.text str) nav_button classes str action = btn classes action (HH.text str)

View File

@ -0,0 +1,104 @@
-- | `App.NavigationInterface` is the navbar module.
-- |
-- | This module is required since some javascript is needed to toggle display of hidden resources.
-- | On mobile, a burger menu is displayed and hides the navigation buttons.
-- | On desktop, there is no need for this, all the navigation buttons are displayed by default.
module App.NavigationInterface where
import Prelude (Unit, not, ($), discard, pure)
import App.Nav as Nav
-- import Data.Array as A
import Data.Maybe (Maybe(..))
-- import Data.Either (Either(..))
import Effect.Aff.Class (class MonadAff)
import Halogen as H
--import Halogen.HTML as HH
--import Halogen.HTML.Events as HE
--import Halogen.HTML.Properties as HP
import Bulma as Bulma
import App.Pages (Page(..))
import App.LogMessage (LogMessage)
data Output
= Log LogMessage
-- | Once someone clicks on a routing button, `App.Container` needs to know.
| Routing Page
-- | Once someone clicks on a the Disconnection button, `App.Container` needs to know.
| Disconnection
-- | The component needs to know when the user is logged or not.
data Query a = ToggleLogged Boolean a
type Slot = H.Slot Query Output
type Input = Unit
data Action
-- | `ToggleMenu`: display or hide the content of the burger menu.
= ToggleMenu
-- | The navigation interface must be informed when the client wants to change page.
-- | The request will be propagated to the parent (`App.Container`).
-- | (`Navigate` is `App.Container.Routing`)
| Navigate Page
-- | The navigation interface must be informed when the client wants to disconnect.
-- | The request will be propagated to the parent (`App.Container`).
-- | (`UnLog` is `App.Container.Disconnection`)
| UnLog
-- | State is composed of:
-- | - `logged`, a boolean to toggle the display of some parts of the menu.
-- | - `active`, a boolean to toggle the display of the menu.
type State = { logged :: Boolean, active :: Boolean }
component :: forall m. MonadAff m => H.Component Query Input Output m
component =
H.mkComponent
{ initialState
, render
, eval: H.mkEval $ H.defaultEval { handleAction = handleAction
, handleQuery = handleQuery
}
}
initialState :: Input -> State
initialState _ = { logged: false, active: false }
render :: forall m. State -> H.ComponentHTML Action () m
render { logged, active }
= Bulma.section_small
[ case active of
true -> Bulma.btn "ACTIVE" ToggleMenu
false -> Bulma.alert_btn "NOT ACTIVE" ToggleMenu
, render_nav
]
where
-- TODO: this is needed to show the authd admin button
admin = true
render_nav :: forall childslots monad. H.ComponentHTML Action childslots monad
render_nav = Nav.netlibre_navbar logged admin
(Navigate Home)
(Navigate DomainList)
(Navigate Administration)
(Navigate Authentication)
(Navigate Registration)
(Navigate MailValidation)
UnLog
handleAction :: forall m. MonadAff m => Action -> H.HalogenM State Action () Output m Unit
handleAction = case _ of
ToggleMenu -> H.modify_ \state -> state { active = not state.active }
-- | Page change.
Navigate page -> H.raise $ Routing page
UnLog -> H.raise $ Disconnection
handleQuery :: forall a m. MonadAff m => Query a -> H.HalogenM State Action () Output m (Maybe a)
handleQuery = case _ of
ToggleLogged islogged a -> do
H.modify_ _ { logged = islogged }
pure (Just a)

12
src/App/Pages.purs Normal file
View File

@ -0,0 +1,12 @@
module App.Pages where
-- | This list will grow in a near future.
-- |
-- | TODO:
data Page
= Home -- | `Home`: presentation of the project.
| Authentication -- | `Authentication`: authentication page.
| Registration -- | `Registration`: to register new people.
| MailValidation -- | `MailValidation`: to validate email addresses (via a token).
| DomainList -- | `DomainList`: to list owned domains and to ask for new domains.
| Zone String -- | `Zone`: to manage a zone.
| Administration -- | `Administration`: administration page (for both `authd` and `dnsmanagerd`).