refactor(techdemo): shorten generated resource paths

Import scoped generated modules at the page boundary so handlers and tests read as local slots/forms/handles/classes without hiding ownership or adding framework machinery.

req: component/003

req: dx/006
This commit is contained in:
slhx agent
2026-06-01 22:39:52 +02:00
parent f3706a440e
commit e9c717844d
2 changed files with 43 additions and 41 deletions
+14 -15
View File
@@ -3,7 +3,9 @@ pub mod ui {}
#[cfg(test)]
mod tests {
use super::ui;
use super::ui::control_center::{forms, handles, slots};
use super::ui::issue_card::handles as card_handles;
use super::ui::issue_lane::events as lane_events;
use hemplate::Hemplate;
use slhx::{Effect, IntoEffect, Payload, RenderSlotExt};
use slhx_test::inspect;
@@ -28,14 +30,14 @@ mod tests {
fn techdemo_uses_generated_slots_for_multi_target_updates() {
fn update() -> impl IntoEffect {
(
ui::control_center::slots::hero_metrics.render(&FastMetric { label: "fast" }),
ui::control_center::slots::notice.text("typed"),
slots::hero_metrics.render(&FastMetric { label: "fast" }),
slots::notice.text("typed"),
)
}
let batch = inspect(update());
assert!(batch.has_slot(ui::control_center::slots::hero_metrics));
assert!(batch.has_slot(ui::control_center::slots::notice));
assert!(batch.has_slot(slots::hero_metrics));
assert!(batch.has_slot(slots::notice));
}
// req: examples/001 req: form/001 req: form/004 req: form/006 req: derive_handler/003
@@ -43,34 +45,31 @@ mod tests {
fn techdemo_form_handler_is_checked_against_hemplate_form() {
#[slhx::handler]
fn launch_work(_form: slhx::Form<LaunchWork>) -> impl IntoEffect {
ui::control_center::slots::notice.text("queued")
slots::notice.text("queued")
}
let batch = inspect(launch_work(LaunchWork::FORM));
assert!(batch.has_slot(ui::control_center::slots::notice));
assert!(batch.has_slot(slots::notice));
assert!(matches!(batch.ops(), [Effect::Put { payload: Payload::Text(_), .. }]));
}
// req: examples/001 req: form/002 req: codegen/003
#[test]
fn techdemo_exports_form_and_interaction_handles() {
assert_ne!(
ui::control_center::handles::launch_work.id(),
ui::issue_card::handles::advance_work.id()
);
assert_ne!(handles::launch_work.id(), card_handles::advance_work.id());
assert_eq!(
ui::control_center::forms::launch_work.field("title").resource,
ui::control_center::forms::launch_work.id()
forms::launch_work.field("title").resource,
forms::launch_work.id()
);
}
// req: codegen/006
#[test]
fn techdemo_exports_generated_event_constants() {
assert_eq!(ui::issue_lane::events::drop.as_str(), "drop");
assert_eq!(lane_events::drop.as_str(), "drop");
assert!(matches!(
slhx::event(ui::issue_lane::events::drop, "card-1"),
slhx::event(lane_events::drop, "card-1"),
Effect::Emit { name, payload } if name == "drop" && payload == "card-1"
));
}
+29 -26
View File
@@ -10,6 +10,9 @@ use slhx_axum::{
PageRequest,
};
use slhx_techdemo::ui;
use slhx_techdemo::ui::control_center::{classes, forms, handles, slots};
use slhx_techdemo::ui::issue_card::handles as card_handles;
use slhx_techdemo::ui::issue_lane::handles as lane_handles;
use std::collections::{BTreeMap, VecDeque};
use std::convert::Infallible;
use std::net::SocketAddr;
@@ -266,13 +269,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.render(&LiveFeed { tick: 1 });
let effect = slots::live_feed.render(&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.render(&LiveFeed { tick });
let effect = slots::live_feed.render(&LiveFeed { tick });
Some((Ok::<_, Infallible>(effect.into_batch(ui::BUILD_FINGERPRINT)), tick + 1))
})
.boxed();
@@ -281,7 +284,7 @@ async fn events(Query(params): Query<BTreeMap<String, String>>) -> impl IntoResp
fn registry(shared: Arc<Shared>) -> HandlerRegistry {
HandlerRegistry::new(ui::BUILD_FINGERPRINT)
.register_handle(ui::control_center::handles::launch_work, {
.register_handle(handles::launch_work, {
let shared = shared.clone();
move |form| {
// req: form/002 req: examples/001
@@ -300,7 +303,7 @@ fn registry(shared: Arc<Shared>) -> HandlerRegistry {
demo_effects(&demo, "Launch accepted · 4 targets updated")
}
})
.register_handle(ui::issue_card::handles::advance_work, {
.register_handle(card_handles::advance_work, {
let shared = shared.clone();
move |form| {
// req: list/003 req: examples/001
@@ -318,7 +321,7 @@ fn registry(shared: Arc<Shared>) -> HandlerRegistry {
demo_effects(&demo, "Pipeline advanced")
}
})
.register_handle(ui::issue_lane::handles::move_to_lane, {
.register_handle(lane_handles::move_to_lane, {
let shared = shared.clone();
move |form| {
// req: list/003 req: examples/001
@@ -340,7 +343,7 @@ fn registry(shared: Arc<Shared>) -> HandlerRegistry {
demo_effects(&demo, "Drag-and-drop move persisted")
}
})
.register_handle(ui::issue_card::handles::delete_work, {
.register_handle(card_handles::delete_work, {
let shared = shared.clone();
move |form| {
// req: list/003 req: examples/001
@@ -359,7 +362,7 @@ fn registry(shared: Arc<Shared>) -> HandlerRegistry {
demo_effects(&demo, "Card removed")
}
})
.register_handle(ui::issue_card::handles::spotlight_work, {
.register_handle(card_handles::spotlight_work, {
let shared = shared.clone();
move |form| {
// req: examples/001
@@ -374,23 +377,23 @@ fn registry(shared: Arc<Shared>) -> HandlerRegistry {
demo_effects(&demo, "Inspector focused")
}
})
.register_handle(ui::control_center::handles::simulate_push, {
.register_handle(handles::simulate_push, {
let shared = shared.clone();
move |_| {
// req: push/003 req: examples/001
let mut demo = shared.demo.lock().unwrap();
demo.log("Simulated push event produced the same EffectBatch shape");
(
ui::control_center::slots::live_feed.render(&LiveFeed {
slots::live_feed.render(&LiveFeed {
tick: demo.activity.len() as u64,
}),
ui::control_center::slots::activity.render(&activity_view(&demo)),
ui::control_center::slots::notice.text("Push simulated · no client app code"),
slots::activity.render(&activity_view(&demo)),
slots::notice.text("Push simulated · no client app code"),
slhx::event("slhx:island-orbit", island_snapshot(&demo)),
)
}
})
.register_handle(ui::control_center::handles::reset_demo, {
.register_handle(handles::reset_demo, {
let shared = shared.clone();
move |_| {
// req: examples/001
@@ -411,12 +414,12 @@ 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.render(&hero_view(demo)),
ui::control_center::slots::board.html(render_board(demo)),
ui::control_center::slots::activity.render(&activity_view(demo)),
ui::control_center::slots::inspector.render(&inspector_view(demo)),
ui::control_center::slots::notice.text(notice),
ui::control_center::forms::launch_work.clear("title"),
slots::hero_metrics.render(&hero_view(demo)),
slots::board.html(render_board(demo)),
slots::activity.render(&activity_view(demo)),
slots::inspector.render(&inspector_view(demo)),
slots::notice.text(notice),
forms::launch_work.clear("title"),
slhx::event("slhx:island-orbit", island_snapshot(demo)),
)
}
@@ -485,7 +488,7 @@ fn board_view(demo: &DemoState) -> BoardLanes {
.iter()
.enumerate()
.map(|(idx, (lane_id, title, description))| IssueLane {
class: ui::control_center::classes::lane,
class: classes::lane,
lane_id,
title,
description,
@@ -510,11 +513,11 @@ fn issue_card(item: &WorkItem, selected: bool) -> IssueCard {
IssueCard {
class: if selected {
CssClasses::from([
ui::control_center::classes::work_card,
ui::control_center::classes::is_selected,
classes::work_card,
classes::is_selected,
])
} else {
CssClasses::from(ui::control_center::classes::work_card)
CssClasses::from(classes::work_card)
},
id: item.id,
title: item.title.clone(),
@@ -584,7 +587,7 @@ fn architecture_activity() -> SafeHtml {
fn render_control_center(page: ControlCenter) -> String {
// req: html_safety/002 req: view/001 req: component/003
ui::control_center::render_html(&page).into_string()
ui::render_html(&page).into_string()
}
fn render_template(template: &impl Hemplate) -> String {
@@ -666,9 +669,9 @@ mod tests {
#[test]
fn generated_css_class_flows_through_hemplate_dynamic_attribute() {
let board = render_board(&DemoState::default());
assert_eq!(ui::control_center::classes::lane.as_str(), "lane");
assert_eq!(ui::control_center::classes::work_card.as_str(), "work-card");
assert_eq!(ui::control_center::classes::is_selected.as_str(), "is-selected");
assert_eq!(classes::lane.as_str(), "lane");
assert_eq!(classes::work_card.as_str(), "work-card");
assert_eq!(classes::is_selected.as_str(), "is-selected");
let document = Html::parse_fragment(board.as_str());
assert_eq!(document.select(&selector(".lanes > section.lane")).count(), 3);