use leptos::prelude::*; use leptos_meta::{provide_meta_context, MetaTags, Stylesheet, Title}; use leptos_router::{ components::{A, ParentRoute, Route, Router, Routes}, hooks::use_query_map, path }; use crate::users::User; #[server] pub async fn test_retrieve() -> Result { use leptos::server_fn::error::NoCustomError; tokio::time::sleep(tokio::time::Duration::from_millis(1000)).await; let start = std::time::SystemTime::now(); let since_the_epoch = start .duration_since(std::time::UNIX_EPOCH) .map_err(|e| ServerFnError::::ServerError(e.to_string()))? .as_secs(); Ok(since_the_epoch) } #[server] pub async fn me() -> Result, ServerFnError> { let user = crate::db::user::get_auth_session().await?; Ok(user.map(|user| User { user_id: user.user_id, user_name: user.user_name })) } #[server] async fn login(username: String, password: String, next: String) -> Result<(), ServerFnError> { crate::db::user::create_auth_session(username, password).await?; leptos_axum::redirect(&next); Ok(()) } #[server] async fn logout() -> Result<(), ServerFnError> { crate::db::user::destroy_auth_session().await } pub fn shell(options: LeptosOptions) -> impl IntoView { view! { } } #[component] pub fn App() -> impl IntoView { provide_meta_context(); let login = ServerAction::::new(); let (user_res, set_user_res) = signal(None); let user = Resource::new( move || { login.version().get() }, |_| async { #[cfg(feature = "ssr")] tracing::info!("Checking user account"); #[cfg(feature = "hydrate")] leptos::logging::log!("Checking user account"); me().await } ); Effect::new(move || { let u = user.get(); set_user_res(u.map(|u2| u2.ok()).flatten().flatten()); }); provide_context(user_res); Effect::new(move || { leptos::logging::log!("User resource: {:?}", user.get()); }); crate::beacons::provide_beacon_resources(); view! { <Router> <nav> <h1>"Sparse control"</h1> <A href="/">"Home"</A> <Suspense fallback=|| ()> {move || user .get() .map(|err| err.ok()) .flatten() .flatten() .map(|_| view! { <A href="/beacons">"Beacon management"</A> <A href="/users">"Users"</A> <a href="#" on:click=move |_| { leptos::task::spawn_local(async move { let _ = logout().await; user.refetch(); }); } > "Log out" </a> })} {move || user .get() .map(|err| err.ok()) .flatten() .flatten() .is_none() .then(|| view! { <A href="/login">"Log in"</A> })} </Suspense> </nav> <crate::beacons::BeaconSidebar /> <Routes fallback=|| "Page not found.".into_view()> <Route path=path!("users") view=crate::users::UserView /> <Route path=path!("login") view=move || view! { <LoginPage login/> }/> <ParentRoute path=path!("beacons") view=crate::beacons::BeaconView> <Route path=path!("categories") view=crate::beacons::CategoriesView/> <Route path=path!("commands") view=crate::beacons::CommandsView/> <Route path=path!("configs") view=crate::beacons::ConfigsView/> <Route path=path!("templates") view=crate::beacons::TemplatesView/> <Route path=path!("instances") view=crate::beacons::InstancesView/> <Route path=path!("listeners") view=crate::beacons::ListenersView/> <Route path=path!("") view=|| view! { <p>"Select a menu item on the left to get started"</p> }/> </ParentRoute> <Route path=path!("") view=HomePage/> </Routes> </Router> } } #[component] fn LoginPage(login: ServerAction<Login>) -> impl IntoView { let next = move || use_query_map().read().get("next").unwrap_or("/".to_string()); view! { <main class="login"> {move || match login.value().get() { Some(Ok(_)) => None, None => None, Some(Err(e)) => Some(view! { <div> "Error signing in: " {format!("{e:?}")} </div> }) }} <ActionForm action=login> <label>"Username"</label> <input type="text" name="username" /> <label>"Password"</label> <input type="password" name="password" /> <div></div> <input type="submit" value="Submit" /> <input type="hidden" value=next name="next" /> </ActionForm> </main> } } /// Renders the home page of your application. #[component] fn HomePage() -> impl IntoView { view! { <main class="main"> <h1>"Welcome to sparse!"</h1> <p>"To get started:"</p> <ol> <li>"Sign in"</li> <li>"Go to beacon management"</li> <li>"Create a listener"</li> <li>"(Optional) Create a category"</li> <li>"Create a template"</li> <li>"Download the installer"</li> <li>"Run the installer on a target system"</li> </ol> </main> } }