use crate::{ components::{ change_password::ChangePasswordForm, create_group::CreateGroupForm, create_user::CreateUserForm, group_details::GroupDetails, group_table::GroupTable, login::LoginForm, logout::LogoutButton, reset_password_step1::ResetPasswordStep1Form, reset_password_step2::ResetPasswordStep2Form, router::{AppRoute, Link, Redirect}, user_details::UserDetails, user_table::UserTable, }, infra::{api::HostService, cookies::get_cookie}, }; use gloo_console::error; use wasm_bindgen::prelude::*; use yew::{ function_component, html::Scope, prelude::{html, Component, Html}, Context, }; use yew_router::{ prelude::{History, Location}, scope_ext::RouterScopeExt, BrowserRouter, Switch, }; #[wasm_bindgen] extern "C" { #[wasm_bindgen(js_namespace = darkmode)] fn toggleDarkMode(doSave: bool); #[wasm_bindgen] fn inDarkMode() -> bool; } #[function_component(DarkModeToggle)] pub fn dark_mode_toggle() -> Html { html! {
} } #[function_component(AppContainer)] pub fn app_container() -> Html { html! { } } pub struct App { user_info: Option<(String, bool)>, redirect_to: Option, password_reset_enabled: Option, } pub enum Msg { Login((String, bool)), Logout, PasswordResetProbeFinished(anyhow::Result), } impl Component for App { type Message = Msg; type Properties = (); fn create(ctx: &Context) -> Self { let app = Self { user_info: get_cookie("user_id") .unwrap_or_else(|e| { error!(&e.to_string()); None }) .and_then(|u| { get_cookie("is_admin") .map(|so| so.map(|s| (u, s == "true"))) .unwrap_or_else(|e| { error!(&e.to_string()); None }) }), redirect_to: Self::get_redirect_route(ctx), password_reset_enabled: None, }; ctx.link().send_future(async move { Msg::PasswordResetProbeFinished(HostService::probe_password_reset().await) }); app.apply_initial_redirections(ctx); app } fn update(&mut self, ctx: &Context, msg: Self::Message) -> bool { let history = ctx.link().history().unwrap(); match msg { Msg::Login((user_name, is_admin)) => { self.user_info = Some((user_name.clone(), is_admin)); history.push(self.redirect_to.take().unwrap_or_else(|| { if is_admin { AppRoute::ListUsers } else { AppRoute::UserDetails { user_id: user_name.clone(), } } })); } Msg::Logout => { self.user_info = None; self.redirect_to = None; history.push(AppRoute::Login); } Msg::PasswordResetProbeFinished(Ok(enabled)) => { self.password_reset_enabled = Some(enabled); } Msg::PasswordResetProbeFinished(Err(err)) => { self.password_reset_enabled = Some(false); error!(&format!( "Could not probe for password reset support: {err:#}" )); } } true } fn view(&self, ctx: &Context) -> Html { let link = ctx.link().clone(); let is_admin = self.is_admin(); let password_reset_enabled = self.password_reset_enabled; html! {
{self.view_banner(ctx)}
render={Switch::render(move |routes| Self::dispatch_route(routes, &link, is_admin, password_reset_enabled))} />
{self.view_footer()}
} } } impl App { // Get the page to land on after logging in, defaulting to the index. fn get_redirect_route(ctx: &Context) -> Option { let route = ctx.link().history().unwrap().location().route::(); route.filter(|route| { !matches!( route, AppRoute::Index | AppRoute::Login | AppRoute::StartResetPassword | AppRoute::FinishResetPassword { token: _ } ) }) } fn apply_initial_redirections(&self, ctx: &Context) { let history = ctx.link().history().unwrap(); let route = history.location().route::(); let redirection = match (route, &self.user_info, &self.redirect_to) { ( Some(AppRoute::StartResetPassword | AppRoute::FinishResetPassword { token: _ }), _, _, ) => { if self.password_reset_enabled == Some(false) { Some(AppRoute::Login) } else { None } } (None, _, _) | (_, None, _) => Some(AppRoute::Login), // User is logged in, a URL was given, don't redirect. (_, Some(_), Some(_)) => None, (_, Some((user_name, is_admin)), None) => { if *is_admin { Some(AppRoute::ListUsers) } else { Some(AppRoute::UserDetails { user_id: user_name.clone(), }) } } }; if let Some(redirect_to) = redirection { history.push(redirect_to); } } fn dispatch_route( switch: &AppRoute, link: &Scope, is_admin: bool, password_reset_enabled: Option, ) -> Html { match switch { AppRoute::Login => html! { }, AppRoute::CreateUser => html! { }, AppRoute::Index | AppRoute::ListUsers => html! {
{"Create a user"}
}, AppRoute::CreateGroup => html! { }, AppRoute::ListGroups => html! {
{"Create a group"}
}, AppRoute::GroupDetails { group_id } => html! { }, AppRoute::UserDetails { user_id } => html! { }, AppRoute::ChangePassword { user_id } => html! { }, AppRoute::StartResetPassword => match password_reset_enabled { Some(true) => html! { }, Some(false) => { html! { } } None => html! {}, }, AppRoute::FinishResetPassword { token } => match password_reset_enabled { Some(true) => html! { }, Some(false) => { html! { } } None => html! {}, }, } } fn view_banner(&self, ctx: &Context) -> Html { html! {

{"LLDAP"}

{ self.view_user_menu(ctx) }
} } fn view_user_menu(&self, ctx: &Context) -> Html { if let Some((user_id, _)) = &self.user_info { let link = ctx.link(); html! { } } else { html! {} } } fn view_footer(&self) -> Html { html! { } } fn is_admin(&self) -> bool { match &self.user_info { None => false, Some((_, is_admin)) => *is_admin, } } }