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 hemplate::Hemplate;
|
||||||
use hemx::{Html, IntoEffect};
|
use hemx::{Html, IntoEffect};
|
||||||
use hemx_axum::{interactions, Form, HandlerRegistry};
|
use hemx_axum::{state_interactions, Form, HandlerRegistry};
|
||||||
use hemx_host::{
|
use hemx_host::{
|
||||||
browser_pwa_host_profile, native_shell_host_profile, Capability, CapabilityManifest,
|
browser_pwa_host_profile, native_shell_host_profile, Capability, CapabilityManifest,
|
||||||
CapabilityShape, CapabilityUse, HapticPattern, HostCall, HostCallId, HostEvent,
|
CapabilityShape, CapabilityUse, HapticPattern, HostCall, HostCallId, HostEvent,
|
||||||
@@ -365,8 +365,7 @@ pub struct RecordNoteInput {
|
|||||||
|
|
||||||
pub fn registry(state: AppState) -> HandlerRegistry {
|
pub fn registry(state: AppState) -> HandlerRegistry {
|
||||||
// req: codegen/002 req: examples/001
|
// req: codegen/002 req: examples/001
|
||||||
interactions(ui::BUILD_FINGERPRINT)
|
state_interactions(ui::BUILD_FINGERPRINT, state)
|
||||||
.with_state(state)
|
|
||||||
.on_state(ui::workout::complete_set, complete_set)
|
.on_state(ui::workout::complete_set, complete_set)
|
||||||
.on(ui::workout::change_weight, change_weight_form)
|
.on(ui::workout::change_weight, change_weight_form)
|
||||||
.on_state(ui::workout::skip_exercise, skip_exercise)
|
.on_state(ui::workout::skip_exercise, skip_exercise)
|
||||||
|
|||||||
@@ -460,6 +460,14 @@ pub const fn interactions(fingerprint: BuildFingerprint) -> HandlerRegistry {
|
|||||||
HandlerRegistry::new(fingerprint)
|
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 {
|
impl InteractionRequest {
|
||||||
pub fn dispatch(
|
pub fn dispatch(
|
||||||
self,
|
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")]);
|
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]
|
#[test]
|
||||||
fn interaction_request_dispatches_typed_form_inputs() {
|
fn interaction_request_dispatches_typed_form_inputs() {
|
||||||
// req: axum_integration/003 req: form/004 req: canonical_authoring/003
|
// req: axum_integration/003 req: form/004 req: canonical_authoring/003
|
||||||
|
|||||||
Reference in New Issue
Block a user