1use serde::Serialize;
2use serde_json::{Map, Value};
3
4pub const HX_TRIGGER_HEADER: &str = "HX-Trigger";
5
6#[derive(Clone, Debug, Serialize)]
7pub struct MessageEvent<'a> {
8 pub kind: &'a str,
9 pub msg: &'a str,
10}
11
12#[derive(Clone, Debug)]
13pub enum Trigger<'a> {
14 Toast(MessageEvent<'a>),
15 Echo(MessageEvent<'a>),
16 Custom { name: &'a str, value: Value },
17}
18
19impl<'a> Trigger<'a> {
20 pub fn toast(kind: &'a str, msg: &'a str) -> Self {
21 Self::Toast(MessageEvent { kind, msg })
22 }
23
24 pub fn echo(kind: &'a str, msg: &'a str) -> Self {
25 Self::Echo(MessageEvent { kind, msg })
26 }
27
28 pub fn custom(name: &'a str, value: Value) -> Self {
29 Self::Custom { name, value }
30 }
31}
32
33pub fn trigger_header(triggers: &[Trigger<'_>]) -> serde_json::Result<String> {
34 let mut map = Map::new();
35
36 for trigger in triggers {
37 match trigger {
38 Trigger::Toast(event) => {
39 map.insert("wfToast".to_owned(), serde_json::to_value(event)?);
40 }
41 Trigger::Echo(event) => {
42 map.insert("wfEcho".to_owned(), serde_json::to_value(event)?);
43 }
44 Trigger::Custom { name, value } => {
45 map.insert((*name).to_owned(), value.clone());
46 }
47 }
48 }
49
50 Ok(Value::Object(map).to_string())
51}
52
53pub fn trigger_header_pair(triggers: &[Trigger<'_>]) -> serde_json::Result<(&'static str, String)> {
54 trigger_header(triggers).map(|value| (HX_TRIGGER_HEADER, value))
55}
56
57pub fn toast_header(kind: &str, msg: &str) -> String {
58 trigger_header(&[Trigger::toast(kind, msg)])
59 .expect("serializing a Wave Funk toast trigger should not fail")
60}
61
62pub fn echo_header(kind: &str, msg: &str) -> String {
63 trigger_header(&[Trigger::echo(kind, msg)])
64 .expect("serializing a Wave Funk echo trigger should not fail")
65}
66
67#[cfg(test)]
68mod tests {
69 use super::*;
70
71 #[test]
72 fn builds_hx_trigger_payload() {
73 let header = trigger_header(&[Trigger::toast("ok", "Saved.")]).unwrap();
74 assert_eq!(header, r#"{"wfToast":{"kind":"ok","msg":"Saved."}}"#);
75 }
76
77 #[test]
78 fn builds_hx_trigger_response_header_pair() {
79 let header = trigger_header_pair(&[
80 Trigger::toast("ok", "Saved."),
81 Trigger::echo("info", "Queued."),
82 ])
83 .unwrap();
84
85 assert_eq!(header.0, HX_TRIGGER_HEADER);
86 let value: Value = serde_json::from_str(&header.1).unwrap();
87 assert_eq!(value["wfToast"]["kind"], "ok");
88 assert_eq!(value["wfToast"]["msg"], "Saved.");
89 assert_eq!(value["wfEcho"]["kind"], "info");
90 assert_eq!(value["wfEcho"]["msg"], "Queued.");
91 }
92}