feat(build): make generated page helper canonical
Move canonical examples and docs snippets from raw render/page calls to generated ui::page helpers, hide generated render behind doc(hidden), and let form resources participate in generated target inspection for tests. req: canonical_authoring/005 req: dx/006 req: codegen/002 req: public_api/002 req: test/001
This commit is contained in:
+1
-1
@@ -94,7 +94,7 @@ use ui::board::{forms, targets};
|
||||
|
||||
targets::card.replace(card.id, &CardView::from(card));
|
||||
forms::create_card.clear("title");
|
||||
ui::render(&BoardView::from(board));
|
||||
ui::page(&BoardView::from(board));
|
||||
```
|
||||
|
||||
No string desync. No manual ids. The generated module owns the names.
|
||||
|
||||
@@ -37,7 +37,7 @@ mod tests {
|
||||
// req: html_safety/002 req: view/001 req: test/005
|
||||
#[test]
|
||||
fn kanban_board_test_payload_is_rendered_by_a_hemplate_view() {
|
||||
let html = super::ui::render(&empty_board());
|
||||
let html = super::ui::page(&empty_board());
|
||||
let document = Html::parse_fragment(html.as_str());
|
||||
assert_eq!(document.select(&selector(".columns")).count(), 1);
|
||||
}
|
||||
|
||||
@@ -281,15 +281,15 @@ fn parse_column(value: Option<&str>) -> usize {
|
||||
|
||||
fn page_html(board: &BoardState) -> Html {
|
||||
// req: html_safety/002 req: view/001
|
||||
board_ui::render(&Board {
|
||||
board_ui::page(&Board {
|
||||
options: render_options(),
|
||||
board: ui::render(&board_view(board)),
|
||||
board: ui::page(&board_view(board)),
|
||||
})
|
||||
}
|
||||
|
||||
fn shell(body: Html) -> Html {
|
||||
// req: html_safety/001 req: html_safety/002 req: axum_integration/001
|
||||
hemx::page(&AppShell {
|
||||
ui::page(&AppShell {
|
||||
runtime_src: runtime_js_path(),
|
||||
body,
|
||||
})
|
||||
@@ -297,7 +297,7 @@ fn shell(body: Html) -> Html {
|
||||
|
||||
fn render_options() -> Html {
|
||||
// req: html_safety/002 req: view/001
|
||||
ui::render(&ColumnOptions {
|
||||
ui::page(&ColumnOptions {
|
||||
options: COLUMNS
|
||||
.iter()
|
||||
.map(|(id, title)| ColumnOption { id, title })
|
||||
@@ -385,7 +385,7 @@ mod tests {
|
||||
}],
|
||||
};
|
||||
|
||||
let html = ui::render(&board_view(&board));
|
||||
let html = ui::page(&board_view(&board));
|
||||
let document = Html::parse_fragment(html.as_str());
|
||||
assert_eq!(
|
||||
document
|
||||
@@ -417,7 +417,7 @@ mod tests {
|
||||
// req: html_safety/002 req: view/001 req: test/005
|
||||
#[test]
|
||||
fn presence_payload_is_rendered_by_a_hemplate_view() {
|
||||
let html = ui::render(&Presence { count: 7 });
|
||||
let html = ui::page(&Presence { count: 7 });
|
||||
let document = Html::parse_fragment(html.as_str());
|
||||
assert_eq!(
|
||||
document
|
||||
|
||||
+15
-19
@@ -254,18 +254,18 @@ pub struct AppShell {
|
||||
}
|
||||
|
||||
pub fn home_page(ctx: &AppContext) -> Html {
|
||||
hemx::page(&AppShell {
|
||||
ui::page(&AppShell {
|
||||
title: "hemx SaaS tutorial",
|
||||
runtime_src: runtime_js_path(),
|
||||
body: hemx::page(&Dashboard::from_context(ctx)),
|
||||
body: ui::page(&Dashboard::from_context(ctx)),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn settings_page(ctx: &AppContext) -> Html {
|
||||
hemx::page(&AppShell {
|
||||
ui::page(&AppShell {
|
||||
title: "hemx SaaS tutorial settings",
|
||||
runtime_src: runtime_js_path(),
|
||||
body: hemx::page(&Dashboard::settings(ctx)),
|
||||
body: ui::page(&Dashboard::settings(ctx)),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -330,7 +330,7 @@ fn project_summary(total: usize) -> String {
|
||||
mod tests {
|
||||
use super::*;
|
||||
use hemx_axum::{InteractionForm, InteractionRequest};
|
||||
use hemx_test::{inspect, inspect_batch};
|
||||
use hemx_test::{any_root_selector, inspect, inspect_batch, target_selector};
|
||||
use scraper::{Html as ParsedHtml, Selector};
|
||||
|
||||
fn form<I>(handle: hemx::Handle<I>, fields: &[(&str, &str)]) -> InteractionForm {
|
||||
@@ -353,15 +353,13 @@ mod tests {
|
||||
let html = home_page(&ctx);
|
||||
let document = ParsedHtml::parse_document(html.as_str());
|
||||
|
||||
assert_eq!(document.select(&selector(any_root_selector())).count(), 1);
|
||||
assert_eq!(
|
||||
document
|
||||
.select(&selector("[data-hemx-root='dashboard']"))
|
||||
.count(),
|
||||
1
|
||||
);
|
||||
assert_eq!(
|
||||
document
|
||||
.select(&selector("form[data-hemx-form='new_project']"))
|
||||
.select(&selector(&format!(
|
||||
"form{}",
|
||||
target_selector(dashboard::new_project)
|
||||
)))
|
||||
.count(),
|
||||
1
|
||||
);
|
||||
@@ -389,15 +387,13 @@ mod tests {
|
||||
let html = settings_page(&ctx);
|
||||
let document = ParsedHtml::parse_document(html.as_str());
|
||||
|
||||
assert_eq!(document.select(&selector(any_root_selector())).count(), 1);
|
||||
assert_eq!(
|
||||
document
|
||||
.select(&selector("[data-hemx-root='dashboard']"))
|
||||
.count(),
|
||||
1
|
||||
);
|
||||
assert_eq!(
|
||||
document
|
||||
.select(&selector("[data-hemx-slot='page_panel'] .settings-page"))
|
||||
.select(&selector(&format!(
|
||||
"{} .settings-page",
|
||||
target_selector(dashboard::page_panel)
|
||||
)))
|
||||
.count(),
|
||||
1
|
||||
);
|
||||
|
||||
+10
-10
@@ -268,18 +268,18 @@ fn registry(state: Arc<ExampleState>) -> Registry {
|
||||
fn all_examples() -> Html {
|
||||
// req: html_safety/001 req: html_safety/002 req: component/003
|
||||
Html::join([
|
||||
counter::render(&Counter),
|
||||
hemx::page(&todos_view(&[])),
|
||||
wizard::render(&Wizard),
|
||||
auth::render(&Auth),
|
||||
counter::page(&Counter),
|
||||
ui::page(&todos_view(&[])),
|
||||
wizard::page(&Wizard),
|
||||
auth::page(&Auth),
|
||||
render_page_swap("Welcome", "Welcome"),
|
||||
notifications::render(&Notifications),
|
||||
notifications::page(&Notifications),
|
||||
])
|
||||
}
|
||||
|
||||
fn shell(body: Html) -> Html {
|
||||
// req: html_safety/001 req: html_safety/002 req: axum_integration/001 req: component/003
|
||||
hemx::page(&AppShell {
|
||||
ui::page(&AppShell {
|
||||
runtime_src: runtime_js_path(),
|
||||
body,
|
||||
})
|
||||
@@ -447,7 +447,7 @@ fn todo_summary(todos: &[TodoRecord]) -> String {
|
||||
|
||||
fn render_page_swap(title: &'static str, message: &'static str) -> Html {
|
||||
// req: html_safety/002 req: view/001 req: component/003
|
||||
page_swap::render(&PageSwap {
|
||||
page_swap::page(&PageSwap {
|
||||
content: render_docs_content(message),
|
||||
title,
|
||||
})
|
||||
@@ -455,7 +455,7 @@ fn render_page_swap(title: &'static str, message: &'static str) -> Html {
|
||||
|
||||
fn render_docs_content(message: &'static str) -> Html {
|
||||
// req: html_safety/002 req: view/001 req: component/003
|
||||
hemx::page(&DocsContent { message })
|
||||
ui::page(&DocsContent { message })
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -570,7 +570,7 @@ mod tests {
|
||||
title: "<b>Ship v0</b>".to_owned(),
|
||||
}];
|
||||
|
||||
let html = hemx::page(&todos_view(&todos));
|
||||
let html = ui::page(&todos_view(&todos));
|
||||
let document = Html::parse_fragment(html.as_str());
|
||||
let rows = document
|
||||
.select(&selector(&keyed_items_selector("li")))
|
||||
@@ -590,7 +590,7 @@ mod tests {
|
||||
// req: html_safety/002 req: view/001 req: test/005
|
||||
#[test]
|
||||
fn empty_todos_payload_is_rendered_by_a_hemplate_view() {
|
||||
let html = hemx::page(&todos_view(&[]));
|
||||
let html = ui::page(&todos_view(&[]));
|
||||
let document = Html::parse_fragment(html.as_str());
|
||||
let rows = document
|
||||
.select(&selector(&list_item_selector("")))
|
||||
|
||||
+10
-6
@@ -732,6 +732,7 @@ impl Resources {
|
||||
"{pad} ::hemx::__private::html_trusted(lower(html))\n"
|
||||
));
|
||||
out.push_str(&format!("{pad}}}\n\n"));
|
||||
out.push_str(&format!("{pad}#[doc(hidden)]\n"));
|
||||
out.push_str(&format!(
|
||||
"{pad}pub fn render(view: &impl ::hemplate::Hemplate) -> ::hemx::Html {{\n"
|
||||
));
|
||||
@@ -1733,9 +1734,9 @@ mod tests {
|
||||
));
|
||||
assert!(generated.contains("#[doc(hidden)]\npub fn lower_html"));
|
||||
assert!(generated.contains("pub fn static_fragment(html: &'static str) -> ::hemx::Html"));
|
||||
assert!(
|
||||
generated.contains("pub fn render(view: &impl ::hemplate::Hemplate) -> ::hemx::Html")
|
||||
);
|
||||
assert!(generated.contains(
|
||||
"#[doc(hidden)]\npub fn render(view: &impl ::hemplate::Hemplate) -> ::hemx::Html"
|
||||
));
|
||||
assert!(generated.contains("pub fn page(view: &impl ::hemplate::Hemplate) -> ::hemx::Html"));
|
||||
assert!(generated.contains(
|
||||
"#[doc(hidden)]\npub fn render_html(view: &impl ::hemplate::Hemplate) -> ::hemx::Html"
|
||||
@@ -1846,9 +1847,9 @@ mod tests {
|
||||
));
|
||||
assert!(generated.contains("\n#[doc(hidden)]\npub fn lower_html"));
|
||||
assert!(generated.contains("\npub fn static_fragment(html: &'static str) -> ::hemx::Html"));
|
||||
assert!(
|
||||
generated.contains("\npub fn render(view: &impl ::hemplate::Hemplate) -> ::hemx::Html")
|
||||
);
|
||||
assert!(generated.contains(
|
||||
"\n#[doc(hidden)]\npub fn render(view: &impl ::hemplate::Hemplate) -> ::hemx::Html"
|
||||
));
|
||||
assert!(
|
||||
generated.contains("\npub fn page(view: &impl ::hemplate::Hemplate) -> ::hemx::Html")
|
||||
);
|
||||
@@ -1865,6 +1866,9 @@ mod tests {
|
||||
assert!(generated.contains(" pub const todos: SlotTarget<::std::string::String> = SlotTarget::new(super::advanced::slots::todos);"));
|
||||
assert!(generated.contains(" pub use self::targets::todos;"));
|
||||
assert!(generated.contains(" #[doc(hidden)]\n pub fn lower_html"));
|
||||
assert!(generated.contains(
|
||||
" #[doc(hidden)]\n pub fn render(view: &impl ::hemplate::Hemplate) -> ::hemx::Html"
|
||||
));
|
||||
assert!(
|
||||
generated.contains(" pub fn page(view: &impl ::hemplate::Hemplate) -> ::hemx::Html")
|
||||
);
|
||||
|
||||
@@ -1165,6 +1165,12 @@ impl<T> core::fmt::Display for Form<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> GeneratedTarget for Form<T> {
|
||||
fn __hemx_resource_id(self) -> ResourceId {
|
||||
self.id
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Form<T> {
|
||||
pub const fn new(id: u32) -> Self {
|
||||
Self {
|
||||
|
||||
Reference in New Issue
Block a user