diff --git a/examples/saas/src/lib.rs b/examples/saas/src/lib.rs index 0a87638..8f10a4d 100644 --- a/examples/saas/src/lib.rs +++ b/examples/saas/src/lib.rs @@ -181,6 +181,8 @@ pub struct Dashboard { summary: String, rows: Vec, project_count: usize, + show_projects: bool, + settings: SettingsPage, } impl Dashboard { @@ -191,9 +193,18 @@ impl Dashboard { flash: "Signed in with a demo session".to_owned(), summary: project_summary(projects.len()), project_count: projects.len(), + show_projects: true, + settings: SettingsPage::production_boundaries(), rows: projects.into_iter().map(ProjectRow::from).collect(), } } + + pub fn settings(ctx: &AppContext) -> Self { + let mut dashboard = Self::from_context(ctx); + dashboard.show_projects = false; + dashboard.flash.clear(); + dashboard + } } #[derive(Hemplate)] @@ -226,6 +237,14 @@ pub struct SettingsPage { message: &'static str, } +impl SettingsPage { + fn production_boundaries() -> Self { + Self { + message: "Auth, CSRF, persistence, metrics, and deploy stay explicit app integrations.", + } + } +} + #[derive(Hemplate)] pub struct AppShell { title: &'static str, @@ -239,6 +258,13 @@ pub fn home_page(ctx: &AppContext) -> Html { }) } +pub fn settings_page(ctx: &AppContext) -> Html { + hemx::page(&AppShell { + title: "hemx SaaS tutorial settings", + body: hemx::page(&Dashboard::settings(ctx)), + }) +} + #[hemx::app(dashboard_handlers)] pub fn registry(ctx: AppContext) -> Registry { interactions(ui::BUILD_FINGERPRINT) @@ -277,10 +303,7 @@ mod dashboard_handlers { #[hemx::handler] pub async fn open_settings(State(_ctx): State) -> impl IntoEffect { ( - dashboard::page_panel.put(&SettingsPage { - message: - "Auth, CSRF, persistence, metrics, and deploy stay explicit app integrations.", - }), + dashboard::page_panel.put(&SettingsPage::production_boundaries()), dashboard::nav.set("Settings"), push("/settings"), ) @@ -355,6 +378,31 @@ mod tests { assert!(html.as_str().contains("/metrics.js")); } + #[test] + fn settings_page_renders_the_full_page_fallback() { + // req: examples/001 req: page_swap/002 + let ctx = AppContext::demo(); + let html = settings_page(&ctx); + let document = ParsedHtml::parse_document(html.as_str()); + + assert_eq!( + document + .select(&selector("[data-hemx-root='dashboard']")) + .count(), + 1 + ); + assert_eq!( + document + .select(&selector("[data-hemx-slot='page_panel'] .settings-page")) + .count(), + 1 + ); + assert!(html.as_str().contains("explicit app integrations")); + assert!(!html + .as_str() + .contains("form data-hemx-handle=\"create_project\"")); + } + #[tokio::test] async fn create_project_is_auth_csrf_checked_and_persisted_locally() { // req: examples/001 req: auth/002 req: auth/004 req: form/001 req: failure/004 diff --git a/examples/saas/src/main.rs b/examples/saas/src/main.rs index e964f1b..2206573 100644 --- a/examples/saas/src/main.rs +++ b/examples/saas/src/main.rs @@ -6,7 +6,7 @@ use axum::Router; use futures_util::stream; use hemx::IntoEffect; use hemx_axum::{runtime_js, sse, EffectResponse, InteractionRequest}; -use hemx_saas_example::{home_page, live_status, registry, ui, AppContext}; +use hemx_saas_example::{home_page, live_status, registry, settings_page, ui, AppContext}; use std::collections::BTreeMap; use std::convert::Infallible; @@ -37,7 +37,7 @@ async fn home(State(ctx): State) -> impl IntoResponse { } async fn settings(State(ctx): State) -> impl IntoResponse { - axum::response::Html(home_page(&ctx).into_string()) + axum::response::Html(settings_page(&ctx).into_string()) } async fn interact( diff --git a/examples/saas/templates/dashboard.heml b/examples/saas/templates/dashboard.heml index 8679cd8..26c5618 100644 --- a/examples/saas/templates/dashboard.heml +++ b/examples/saas/templates/dashboard.heml @@ -11,23 +11,28 @@
-
- - - -

-
+
+
+ + + +

+
-

{+ self.flash +}

-

{+ self.summary +}

+

{+ self.flash +}

+

{+ self.summary +}

-
    - -
+
    + +
+
+
+ {+ self.settings +} +