refactor(kanban): render presence with hemplate
Move the kanban SSE presence fragment from Rust raw HTML formatting into a hemplate partial/view and cover the rendered structure with scraper. req: html_safety/002 req: view/001 req: test/005
This commit is contained in:
@@ -10,11 +10,13 @@ path = "src/lib.rs"
|
||||
[dependencies]
|
||||
axum = "0.7"
|
||||
futures-util = "0.3"
|
||||
hemplate = { path = "../../../hemplate/hemplate" }
|
||||
slhx = { path = "../../slhx" }
|
||||
slhx-axum = { path = "../../slhx-axum" }
|
||||
tokio = { version = "1", features = ["macros", "net", "rt-multi-thread", "time"] }
|
||||
|
||||
[dev-dependencies]
|
||||
scraper = "0.23"
|
||||
slhx-test = { path = "../../slhx-test" }
|
||||
|
||||
[build-dependencies]
|
||||
|
||||
@@ -3,6 +3,7 @@ use axum::response::IntoResponse;
|
||||
use axum::routing::get;
|
||||
use axum::Router;
|
||||
use futures_util::{stream, StreamExt};
|
||||
use hemplate::Hemplate;
|
||||
use slhx::{IntoEffect, SafeHtml};
|
||||
use slhx_axum::{runtime_js, sse, DispatchRejection, EffectResponse, HandlerRegistry, InteractionForm, PageRequest};
|
||||
use slhx_kanban_example::ui;
|
||||
@@ -32,6 +33,12 @@ struct Card {
|
||||
column: usize,
|
||||
}
|
||||
|
||||
#[derive(Hemplate)]
|
||||
#[hemplate = "partials"]
|
||||
struct Presence {
|
||||
count: u64,
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
let state = Arc::new(AppState {
|
||||
@@ -80,13 +87,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::board::slots::presence.html(SafeHtml::trusted(render_presence(1)));
|
||||
let effect = ui::board::slots::presence.html(render_presence(1));
|
||||
return sse(stream::iter([Ok::<_, Infallible>(effect.into_batch(ui::BUILD_FINGERPRINT))]).boxed());
|
||||
}
|
||||
|
||||
let batches = stream::unfold(1_u64, |count| async move {
|
||||
tokio::time::sleep(Duration::from_secs(4)).await;
|
||||
let effect = ui::board::slots::presence.html(SafeHtml::trusted(render_presence(count)));
|
||||
let effect = ui::board::slots::presence.html(render_presence(count));
|
||||
Some((Ok::<_, Infallible>(effect.into_batch(ui::BUILD_FINGERPRINT)), count + 1))
|
||||
})
|
||||
.boxed();
|
||||
@@ -247,10 +254,13 @@ fn render_card(card: &Card) -> String {
|
||||
)
|
||||
}
|
||||
|
||||
fn render_presence(count: u64) -> String {
|
||||
format!(
|
||||
r#"<span class="presence">Ada online</span> <span class="presence">Grace online</span> <small>tick #{count}</small>"#
|
||||
)
|
||||
fn render_presence(count: u64) -> SafeHtml {
|
||||
// req: html_safety/002 req: view/001
|
||||
render_html(&Presence { count })
|
||||
}
|
||||
|
||||
fn render_html(template: &impl Hemplate) -> SafeHtml {
|
||||
SafeHtml::trusted(template.render().expect("kanban hemplate partial renders"))
|
||||
}
|
||||
|
||||
fn escape_html(value: &str) -> String {
|
||||
@@ -261,3 +271,28 @@ fn escape_html(value: &str) -> String {
|
||||
.replace('"', """)
|
||||
.replace('\'', "'")
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use scraper::{Html, Selector};
|
||||
|
||||
fn selector(value: &str) -> Selector {
|
||||
Selector::parse(value).expect("test selector parses")
|
||||
}
|
||||
|
||||
// req: html_safety/002 req: view/001 req: test/005
|
||||
#[test]
|
||||
fn presence_payload_is_rendered_by_a_hemplate_view() {
|
||||
let html = render_presence(7);
|
||||
let document = Html::parse_fragment(html.as_str());
|
||||
assert_eq!(document.select(&selector("span.presence")).count(), 2);
|
||||
assert_eq!(
|
||||
document
|
||||
.select(&selector("small"))
|
||||
.next()
|
||||
.map(|small| small.text().collect::<String>()),
|
||||
Some("tick #7".to_owned())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
<span class="presence">Ada online</span> <span class="presence">Grace online</span> <small>tick #{+ self.count +}</small>
|
||||
Reference in New Issue
Block a user