test(techdemo): render slots from hemplate views
Migrate techdemo effect paths and tests from explicit SafeHtml/html payload plumbing to RenderSlotExt view helpers. req: view/001 req: html_safety/002
This commit is contained in:
@@ -5,7 +5,7 @@ pub mod ui {}
|
||||
mod tests {
|
||||
use super::ui;
|
||||
use hemplate::Hemplate;
|
||||
use slhx::{Effect, IntoEffect, Payload, SafeHtml};
|
||||
use slhx::{Effect, IntoEffect, Payload, RenderSlotExt};
|
||||
use slhx_test::inspect;
|
||||
|
||||
#[derive(Hemplate)]
|
||||
@@ -28,7 +28,7 @@ mod tests {
|
||||
fn techdemo_uses_generated_slots_for_multi_target_updates() {
|
||||
fn update() -> impl IntoEffect {
|
||||
(
|
||||
ui::control_center::slots::hero_metrics.html(render_fast_metric("fast")),
|
||||
ui::control_center::slots::hero_metrics.render_view(&FastMetric { label: "fast" }),
|
||||
ui::control_center::slots::notice.text("typed"),
|
||||
)
|
||||
}
|
||||
@@ -38,15 +38,6 @@ mod tests {
|
||||
assert!(batch.has_slot(ui::control_center::slots::notice));
|
||||
}
|
||||
|
||||
fn render_fast_metric(label: &'static str) -> SafeHtml {
|
||||
// req: html_safety/002 req: view/001
|
||||
let mut html = String::new();
|
||||
FastMetric { label }
|
||||
.render_into(&mut html)
|
||||
.expect("techdemo fast metric renders");
|
||||
SafeHtml::trusted(html)
|
||||
}
|
||||
|
||||
// req: examples/001 req: form/001 req: form/004 req: form/006 req: derive_handler/003
|
||||
#[test]
|
||||
fn techdemo_form_handler_is_checked_against_hemplate_form() {
|
||||
|
||||
@@ -4,7 +4,7 @@ use axum::routing::get;
|
||||
use axum::Router;
|
||||
use futures_util::{stream, StreamExt};
|
||||
use hemplate::Hemplate;
|
||||
use slhx::{CssClass, CssClasses, Handle, IntoEffect, SafeHtml};
|
||||
use slhx::{CssClass, CssClasses, Handle, IntoEffect, RenderSlotExt, SafeHtml};
|
||||
use slhx_axum::{
|
||||
runtime_js, sse, DispatchRejection, EffectResponse, HandlerRegistry, InteractionForm,
|
||||
PageRequest,
|
||||
@@ -263,13 +263,13 @@ async fn interact(
|
||||
// req: push/001 req: push/003 req: examples/001
|
||||
async fn events(Query(params): Query<BTreeMap<String, String>>) -> impl IntoResponse {
|
||||
if params.contains_key("once") {
|
||||
let effect = ui::control_center::slots::live_feed.html(live_feed(1));
|
||||
let effect = ui::control_center::slots::live_feed.render_view(&LiveFeed { tick: 1 });
|
||||
return sse(stream::iter([Ok::<_, Infallible>(effect.into_batch(ui::BUILD_FINGERPRINT))]).boxed());
|
||||
}
|
||||
|
||||
let batches = stream::unfold(1_u64, |tick| async move {
|
||||
tokio::time::sleep(Duration::from_secs(4)).await;
|
||||
let effect = ui::control_center::slots::live_feed.html(live_feed(tick));
|
||||
let effect = ui::control_center::slots::live_feed.render_view(&LiveFeed { tick });
|
||||
Some((Ok::<_, Infallible>(effect.into_batch(ui::BUILD_FINGERPRINT)), tick + 1))
|
||||
})
|
||||
.boxed();
|
||||
@@ -378,8 +378,10 @@ fn registry(shared: Arc<Shared>) -> HandlerRegistry {
|
||||
let mut demo = shared.demo.lock().unwrap();
|
||||
demo.log("Simulated push event produced the same EffectBatch shape");
|
||||
(
|
||||
ui::control_center::slots::live_feed.html(live_feed(demo.activity.len() as u64)),
|
||||
ui::control_center::slots::activity.html(render_activity(&demo)),
|
||||
ui::control_center::slots::live_feed.render_view(&LiveFeed {
|
||||
tick: demo.activity.len() as u64,
|
||||
}),
|
||||
ui::control_center::slots::activity.render_view(&activity_view(&demo)),
|
||||
ui::control_center::slots::notice.text("Push simulated · no client app code"),
|
||||
)
|
||||
}
|
||||
@@ -405,10 +407,10 @@ fn update_work(demo: &mut DemoState, id: Option<&str>, update: impl FnOnce(&mut
|
||||
|
||||
fn demo_effects(demo: &DemoState, notice: &'static str) -> impl IntoEffect {
|
||||
(
|
||||
ui::control_center::slots::hero_metrics.html(render_hero(demo)),
|
||||
ui::control_center::slots::board.html(render_board(demo)),
|
||||
ui::control_center::slots::activity.html(render_activity(demo)),
|
||||
ui::control_center::slots::inspector.html(render_inspector(demo)),
|
||||
ui::control_center::slots::hero_metrics.render_view(&hero_view(demo)),
|
||||
ui::control_center::slots::board.render_view(&board_view(demo)),
|
||||
ui::control_center::slots::activity.render_view(&activity_view(demo)),
|
||||
ui::control_center::slots::inspector.render_view(&inspector_view(demo)),
|
||||
ui::control_center::slots::notice.text(notice),
|
||||
ui::control_center::forms::launch_work.clear("title"),
|
||||
)
|
||||
@@ -433,20 +435,25 @@ fn shell(body: String) -> String {
|
||||
render_template(&AppShell { body: SafeHtml::trusted(body) })
|
||||
}
|
||||
|
||||
fn render_hero(demo: &DemoState) -> SafeHtml {
|
||||
fn hero_view(demo: &DemoState) -> HeroMetrics {
|
||||
// req: html_safety/002 req: view/001
|
||||
let shipped = demo.work.iter().filter(|item| item.stage == Stage::Shipped).count();
|
||||
let active = demo.work.iter().filter(|item| item.stage == Stage::Active).count();
|
||||
let impact: u64 = demo.work.iter().map(|item| item.impact as u64).sum();
|
||||
render_html(&HeroMetrics {
|
||||
HeroMetrics {
|
||||
resource_count: 13,
|
||||
active_count: active,
|
||||
shipped_count: shipped,
|
||||
impact_score: impact,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn render_board(demo: &DemoState) -> SafeHtml {
|
||||
fn render_hero(demo: &DemoState) -> SafeHtml {
|
||||
// req: html_safety/002 req: view/001
|
||||
render_html(&hero_view(demo))
|
||||
}
|
||||
|
||||
fn board_view(demo: &DemoState) -> BoardLanes {
|
||||
// req: html_safety/002 req: view/001
|
||||
let lanes = LANES
|
||||
.iter()
|
||||
@@ -466,7 +473,12 @@ fn render_board(demo: &DemoState) -> SafeHtml {
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
render_html(&BoardLanes { lanes })
|
||||
BoardLanes { lanes }
|
||||
}
|
||||
|
||||
fn render_board(demo: &DemoState) -> SafeHtml {
|
||||
// req: html_safety/002 req: view/001
|
||||
render_html(&board_view(demo))
|
||||
}
|
||||
|
||||
fn issue_card(item: &WorkItem, selected: bool) -> IssueCard {
|
||||
@@ -489,14 +501,19 @@ fn issue_card(item: &WorkItem, selected: bool) -> IssueCard {
|
||||
}
|
||||
}
|
||||
|
||||
fn render_activity(demo: &DemoState) -> SafeHtml {
|
||||
fn activity_view(demo: &DemoState) -> ActivityFeed {
|
||||
// req: html_safety/002 req: view/001
|
||||
render_html(&ActivityFeed {
|
||||
ActivityFeed {
|
||||
items: demo.activity.iter().cloned().collect(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn render_inspector(demo: &DemoState) -> SafeHtml {
|
||||
fn render_activity(demo: &DemoState) -> SafeHtml {
|
||||
// req: html_safety/002 req: view/001
|
||||
render_html(&activity_view(demo))
|
||||
}
|
||||
|
||||
fn inspector_view(demo: &DemoState) -> InspectorPanel {
|
||||
// req: html_safety/002 req: view/001
|
||||
let selected = demo
|
||||
.selected_id
|
||||
@@ -512,15 +529,15 @@ fn render_inspector(demo: &DemoState) -> SafeHtml {
|
||||
})
|
||||
},
|
||||
);
|
||||
render_html(&InspectorPanel {
|
||||
InspectorPanel {
|
||||
selected,
|
||||
spotlight: demo.spotlight.clone(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn live_feed(tick: u64) -> SafeHtml {
|
||||
fn render_inspector(demo: &DemoState) -> SafeHtml {
|
||||
// req: html_safety/002 req: view/001
|
||||
render_html(&LiveFeed { tick })
|
||||
render_html(&inspector_view(demo))
|
||||
}
|
||||
|
||||
fn architecture_hero() -> SafeHtml {
|
||||
@@ -674,7 +691,7 @@ mod tests {
|
||||
// req: html_safety/002 req: view/001 req: test/005
|
||||
#[test]
|
||||
fn live_feed_payload_is_rendered_by_a_hemplate_view() {
|
||||
let html = live_feed(7);
|
||||
let html = render_html(&LiveFeed { tick: 7 });
|
||||
let document = Html::parse_fragment(html.as_str());
|
||||
let row = document
|
||||
.select(&selector(".live-row"))
|
||||
|
||||
Reference in New Issue
Block a user