feat(axum): start stateful interactions tersely
Add state_interactions as a small helper for app-owned stateful registries, and use it in the workout exemplar to remove one layer of repetitive route wiring without hiding generated handles or app handlers. req: axum_integration/003 req: ceremony/001 req: dx/003 req: codegen/002 req: examples/001
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
use hemplate::Hemplate;
|
||||
use hemx::{Html, IntoEffect};
|
||||
use hemx_axum::{interactions, Form, HandlerRegistry};
|
||||
use hemx_axum::{state_interactions, Form, HandlerRegistry};
|
||||
use hemx_host::{
|
||||
browser_pwa_host_profile, native_shell_host_profile, Capability, CapabilityManifest,
|
||||
CapabilityShape, CapabilityUse, HapticPattern, HostCall, HostCallId, HostEvent,
|
||||
@@ -365,8 +365,7 @@ pub struct RecordNoteInput {
|
||||
|
||||
pub fn registry(state: AppState) -> HandlerRegistry {
|
||||
// req: codegen/002 req: examples/001
|
||||
interactions(ui::BUILD_FINGERPRINT)
|
||||
.with_state(state)
|
||||
state_interactions(ui::BUILD_FINGERPRINT, state)
|
||||
.on_state(ui::workout::complete_set, complete_set)
|
||||
.on(ui::workout::change_weight, change_weight_form)
|
||||
.on_state(ui::workout::skip_exercise, skip_exercise)
|
||||
|
||||
@@ -460,6 +460,14 @@ pub const fn interactions(fingerprint: BuildFingerprint) -> HandlerRegistry {
|
||||
HandlerRegistry::new(fingerprint)
|
||||
}
|
||||
|
||||
pub fn state_interactions<S>(fingerprint: BuildFingerprint, state: S) -> StateHandlerRegistry<S>
|
||||
where
|
||||
S: Clone + Send + Sync + 'static,
|
||||
{
|
||||
// req: axum_integration/003 req: ceremony/001
|
||||
interactions(fingerprint).with_state(state)
|
||||
}
|
||||
|
||||
impl InteractionRequest {
|
||||
pub fn dispatch(
|
||||
self,
|
||||
|
||||
@@ -232,6 +232,47 @@ fn interaction_request_dispatches_with_concise_handlers_helper() {
|
||||
assert_eq!(response.batch.ops, vec![Slot::<String>::new(3).text("ok")]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn state_interactions_starts_stateful_wiring_without_nested_closures() {
|
||||
// req: axum_integration/003 req: ceremony/001 req: dx/003
|
||||
fn ping(prefix: String) -> impl IntoEffect {
|
||||
Slot::<String>::new(3).text(format!("{prefix}: ping"))
|
||||
}
|
||||
|
||||
fn open(prefix: String, input: OpenProject) -> impl IntoEffect {
|
||||
Slot::<String>::new(3).text(format!("{prefix}: {}", input.project_id.0))
|
||||
}
|
||||
|
||||
let registry = || {
|
||||
hemx_axum::state_interactions(BuildFingerprint(4), "project".to_owned())
|
||||
.on_state(Handle::<()>::new(7), ping)
|
||||
.on(Handle::<()>::new(8), open)
|
||||
.into_registry()
|
||||
};
|
||||
|
||||
let ping_response = InteractionRequest::from(InteractionForm::for_handle(
|
||||
Handle::<()>::new(7),
|
||||
Vec::new(),
|
||||
))
|
||||
.dispatch(registry())
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
ping_response.batch.ops,
|
||||
vec![Slot::<String>::new(3).text("project: ping")]
|
||||
);
|
||||
|
||||
let open_response = InteractionRequest::from(InteractionForm::for_handle(
|
||||
Handle::<()>::new(8),
|
||||
vec![("project_id".to_owned(), "42".to_owned())],
|
||||
))
|
||||
.dispatch(registry())
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
open_response.batch.ops,
|
||||
vec![Slot::<String>::new(3).text("project: 42")]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn interaction_request_dispatches_typed_form_inputs() {
|
||||
// req: axum_integration/003 req: form/004 req: canonical_authoring/003
|
||||
|
||||
Reference in New Issue
Block a user