futuresdr_frontend/ctrl_port/
flowgraph.rs

1use reqwasm::http::Request;
2use wasm_bindgen::prelude::*;
3use yew::prelude::*;
4
5use futuresdr_pmt::FlowgraphDescription;
6
7use crate::ctrl_port::mermaid::Mermaid;
8
9#[wasm_bindgen]
10pub fn add_flowgraph(id: String, url: String) {
11    let document = gloo_utils::document();
12    let div = document.query_selector(&id).unwrap().unwrap();
13    yew::start_app_with_props_in_element::<Flowgraph>(div, Props { url });
14}
15
16pub enum Msg {
17    Error,
18    Reply(FlowgraphDescription),
19}
20
21#[derive(Clone, Properties, Default, PartialEq, Eq)]
22pub struct Props {
23    pub url: String,
24}
25
26pub struct Flowgraph {
27    code: String,
28}
29
30impl Flowgraph {
31    fn endpoint(props: &Props) -> String {
32        format!("{}/api/fg/", props.url)
33    }
34
35    fn callback(ctx: &Context<Self>) {
36        let endpoint = Self::endpoint(ctx.props());
37        gloo_console::log!("flowgraph: sending request");
38
39        ctx.link().send_future(async move {
40            let response = Request::get(&endpoint).send().await;
41
42            if let Ok(response) = response {
43                if let Ok(fg) = response.json().await {
44                    return Msg::Reply(fg);
45                }
46            }
47
48            Msg::Error
49        });
50    }
51
52    fn flowgraph_to_mermaid(fg: FlowgraphDescription) -> String {
53        let mut g = String::from("graph LR;\n");
54
55        for b in fg.blocks.iter() {
56            g.push_str(&format!(
57                "N{}[{}<br/><b>name:</b>{}<br/><b>is blocking</b>:{}];\n",
58                b.id, b.type_name, b.instance_name, b.blocking
59            ));
60        }
61        for e in fg.stream_edges {
62            g.push_str(&format!("N{}-->N{};\n", e.0, e.2));
63        }
64        for e in fg.message_edges {
65            g.push_str(&format!("N{}-.->N{};\n", e.0, e.2));
66        }
67        g
68    }
69}
70
71impl Component for Flowgraph {
72    type Message = Msg;
73    type Properties = Props;
74
75    fn create(_ctx: &Context<Self>) -> Self {
76        Self {
77            code: "flowchart LR".to_string(),
78        }
79    }
80
81    fn rendered(&mut self, ctx: &Context<Self>, first_render: bool) {
82        if first_render {
83            Self::callback(ctx);
84        }
85    }
86
87    fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {
88        match msg {
89            Msg::Error => {
90                self.code = r#"flowchart LR
91                                  id1(Error)
92                                  style id1 color:#000,fill:#f00,stroke:#000,stroke-width:4px
93                            "#
94                .to_string();
95            }
96            Msg::Reply(fg) => {
97                self.code = Self::flowgraph_to_mermaid(fg);
98            }
99        };
100        true
101    }
102
103    fn view(&self, _ctx: &Context<Self>) -> Html {
104        html! {
105            <Mermaid code={self.code.clone()} />
106        }
107    }
108}