mcai_workflow/components/edit_parameter/
edit_string.rs

1use crate::{ActionButton, Button, Modal, ModalMessage};
2use css_in_rust_next::Style;
3use wasm_bindgen::JsCast;
4use web_sys::{Event, EventTarget, HtmlInputElement};
5use yew::{html, Callback, Component, Context, Html, Properties};
6use yew_feather::{plus::Plus, trash_2::Trash2};
7
8#[derive(PartialEq, Properties)]
9pub struct EditStringProperties {
10  pub title: String,
11  pub field_name: String,
12  pub event: Callback<EditStringMessage>,
13  pub value: Option<String>,
14  pub required: bool,
15}
16
17pub enum EditStringMessage {
18  Submit(Option<String>),
19  Cancel,
20}
21
22pub enum InternalMessage {
23  Update(String),
24  Modal(ModalMessage),
25  AddValue,
26  RemoveValue,
27}
28
29pub struct EditString {
30  style: Style,
31  value: Option<String>,
32}
33
34impl Component for EditString {
35  type Message = InternalMessage;
36  type Properties = EditStringProperties;
37
38  fn create(ctx: &Context<Self>) -> Self {
39    let style = Style::create(
40      "Component",
41      concat!(
42        include_str!("edit_style.css"),
43        include_str!("edit_string.css")
44      ),
45    )
46    .unwrap();
47
48    let value = ctx.props().value.clone();
49    EditString { style, value }
50  }
51
52  fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
53    match msg {
54      InternalMessage::Update(value) => {
55        self.value = Some(value);
56        false
57      }
58      InternalMessage::Modal(message) => {
59        let event = match message {
60          ModalMessage::Submit | ModalMessage::Update => {
61            Some(EditStringMessage::Submit(self.value.clone()))
62          }
63          ModalMessage::Cancel => Some(EditStringMessage::Cancel),
64          ModalMessage::Delete => None,
65        };
66
67        if let Some(event) = event {
68          ctx.props().event.emit(event)
69        }
70        false
71      }
72      InternalMessage::AddValue => {
73        self.value = Some("".to_string());
74        true
75      }
76      InternalMessage::RemoveValue => {
77        self.value = None;
78        false
79      }
80    }
81  }
82
83  fn view(&self, ctx: &Context<Self>) -> Html {
84    let input_string_callback = ctx.link().batch_callback(|e: Event| {
85      let target: Option<EventTarget> = e.target();
86      let input = target.and_then(|t| t.dyn_into::<HtmlInputElement>().ok());
87      input.map(|input| InternalMessage::Update(input.value()))
88    });
89
90    let action_buttons = vec![ActionButton::Submit(true)];
91
92    let inner_modal: Html = if ctx.props().required {
93      html!(
94        <input onchange={input_string_callback} value={self.value.clone()} />
95      )
96    } else if let Some(value) = &self.value {
97      html! (
98        <>
99          <div>
100            <input onchange={input_string_callback} value={value.clone()} />
101          </div>
102          <div>
103            <Button
104              label="Remove value"
105              icon={html!(<Trash2 />)}
106              onclick={ctx.link().callback(|_|InternalMessage::RemoveValue)}
107              />
108          </div>
109        </>
110      )
111    } else {
112      html!(
113        <Button
114          label="Add value"
115          icon={html!(<Plus />)}
116          onclick={ctx.link().callback(|_|InternalMessage::AddValue)}
117          />
118      )
119    };
120
121    html!(
122      <Modal
123        event={ctx.link().callback(InternalMessage::Modal)}
124        height="50vh" width="19vw"
125        modal_title={ctx.props().title.clone()}
126        actions={action_buttons}>
127        <div class={self.style.clone()}>
128          <div class="editInput">
129            {inner_modal}
130          </div>
131        </div>
132      </Modal>
133    )
134  }
135}