103 lines
3.7 KiB
Rust
103 lines
3.7 KiB
Rust
use dioxus::prelude::*;
|
|
use dioxus_free_icons::icons::bs_icons::BsBook;
|
|
use dioxus_free_icons::icons::fa_solid_icons::{FaChartLine, FaCubes, FaGears};
|
|
use dioxus_free_icons::Icon;
|
|
|
|
use crate::components::DashboardCard;
|
|
use crate::Route;
|
|
|
|
/// Overview dashboard page rendered inside the `AppShell` layout.
|
|
///
|
|
/// Displays a welcome heading and a grid of quick-access cards
|
|
/// for the main GenAI platform tools.
|
|
#[component]
|
|
pub fn OverviewPage() -> Element {
|
|
// Check authentication status on mount via a server function.
|
|
let auth_check = use_resource(check_auth);
|
|
let navigator = use_navigator();
|
|
|
|
// Once the server responds, redirect unauthenticated users to /auth.
|
|
use_effect(move || {
|
|
if let Some(Ok(false)) = auth_check() {
|
|
navigator.push(NavigationTarget::<Route>::External(
|
|
"/auth?redirect_url=/".into(),
|
|
));
|
|
}
|
|
});
|
|
|
|
match auth_check() {
|
|
// Still waiting for the server to respond.
|
|
None => rsx! {},
|
|
// Not authenticated -- render nothing while the redirect fires.
|
|
Some(Ok(false)) => rsx! {},
|
|
// Authenticated -- render the overview dashboard.
|
|
Some(Ok(true)) => rsx! {
|
|
section { class: "overview-page",
|
|
h1 { class: "overview-heading", "GenAI Dashboard" }
|
|
div { class: "dashboard-grid",
|
|
DashboardCard {
|
|
title: "Documentation".to_string(),
|
|
description: "Guides & API Reference".to_string(),
|
|
href: "#".to_string(),
|
|
icon: rsx! {
|
|
Icon { icon: BsBook, width: 28, height: 28 }
|
|
},
|
|
}
|
|
DashboardCard {
|
|
title: "Langfuse".to_string(),
|
|
description: "Observability & Analytics".to_string(),
|
|
href: "#".to_string(),
|
|
icon: rsx! {
|
|
Icon { icon: FaChartLine, width: 28, height: 28 }
|
|
},
|
|
}
|
|
DashboardCard {
|
|
title: "Langchain".to_string(),
|
|
description: "Agent Framework".to_string(),
|
|
href: "#".to_string(),
|
|
icon: rsx! {
|
|
Icon { icon: FaGears, width: 28, height: 28 }
|
|
},
|
|
}
|
|
DashboardCard {
|
|
title: "Hugging Face".to_string(),
|
|
description: "Browse Models".to_string(),
|
|
href: "#".to_string(),
|
|
icon: rsx! {
|
|
Icon { icon: FaCubes, width: 28, height: 28 }
|
|
},
|
|
}
|
|
}
|
|
}
|
|
},
|
|
// Server error -- surface it so it is not silently swallowed.
|
|
Some(Err(err)) => rsx! {
|
|
p { "Error: {err}" }
|
|
},
|
|
}
|
|
}
|
|
|
|
/// Check whether the current request has an active logged-in session.
|
|
///
|
|
/// # Returns
|
|
///
|
|
/// `true` if the session contains a logged-in user, `false` otherwise.
|
|
///
|
|
/// # Errors
|
|
///
|
|
/// Returns `ServerFnError` if the session cannot be extracted from the request.
|
|
#[server]
|
|
async fn check_auth() -> Result<bool, ServerFnError> {
|
|
use crate::infrastructure::{UserStateInner, LOGGED_IN_USER_SESS_KEY};
|
|
use tower_sessions::Session;
|
|
|
|
// Extract the tower_sessions::Session from the Axum request.
|
|
let session: Session = FullstackContext::extract().await?;
|
|
let user: Option<UserStateInner> = session
|
|
.get(LOGGED_IN_USER_SESS_KEY)
|
|
.await
|
|
.map_err(|e| ServerFnError::new(format!("session read failed: {e}")))?;
|
|
|
|
Ok(user.is_some())
|
|
}
|