mcai_workflow/components/edit_parameter/
edit_requirements.rs

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