mcai_workflow/components/edit_parameter/
edit_string_array.rs1use 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 EditStringArrayProperties {
10 pub title: String,
11 pub field_name: String,
12 pub event: Callback<EditStringArrayMessage>,
13 pub value: Vec<String>,
14}
15
16pub enum EditStringArrayMessage {
17 Submit(Vec<String>),
18 Cancel,
19}
20pub enum InternalMessage {
21 Add,
22 Delete(usize),
23 Update((usize, String)),
24 Modal(ModalMessage),
25}
26
27pub struct EditStringArray {
28 style: Style,
29 value: Vec<String>,
30}
31
32impl Component for EditStringArray {
33 type Message = InternalMessage;
34 type Properties = EditStringArrayProperties;
35
36 fn create(ctx: &Context<Self>) -> Self {
37 let style = Style::create(
38 "Component",
39 concat!(
40 include_str!("edit_style.css"),
41 include_str!("edit_string_array.css")
42 ),
43 )
44 .unwrap();
45
46 let value = ctx.props().value.clone();
47 EditStringArray { style, value }
48 }
49
50 fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
51 match msg {
52 InternalMessage::Add => {
53 self.value.push("".to_string());
54 true
55 }
56 InternalMessage::Delete(index) => {
57 self.value.remove(index);
58 true
59 }
60 InternalMessage::Update((index, value)) => {
61 self.value[index] = value;
62 false
63 }
64 InternalMessage::Modal(message) => {
65 let event = match message {
66 ModalMessage::Submit | ModalMessage::Update => {
67 Some(EditStringArrayMessage::Submit(self.value.clone()))
68 }
69 ModalMessage::Cancel => Some(EditStringArrayMessage::Cancel),
70 ModalMessage::Delete => None,
71 };
72
73 if let Some(event) = event {
74 ctx.props().event.emit(event)
75 }
76 false
77 }
78 }
79 }
80
81 fn view(&self, ctx: &Context<Self>) -> Html {
82 let action_buttons = vec![ActionButton::Submit(true)];
83
84 let inner: Html = self
85 .value
86 .iter()
87 .enumerate()
88 .map(|(index, value)| {
89 let cloned_index = index;
90
91 let callback = ctx.link().batch_callback(move |e: Event| {
92 let target: Option<EventTarget> = e.target();
93 let input = target.and_then(|t| t.dyn_into::<HtmlInputElement>().ok());
94 input.map(|input| InternalMessage::Update((cloned_index, input.value())))
95 });
96
97 html!(
98 <div class="item">
99 <input type="text" value={value.clone()} onchange={callback} />
100 <Button
101 label=""
102 icon={html!(<Trash2 />)}
103 onclick={ctx.link().callback(move |_| InternalMessage::Delete(index))}
104 />
105 </div>
106 )
107 })
108 .collect();
109
110 html!(
111 <Modal
112 event={ctx.link().callback(InternalMessage::Modal)}
113 height="50vh" width="19vw"
114 modal_title={ctx.props().title.clone()}
115 actions={action_buttons}>
116 <div class={self.style.clone()}>
117 {inner}
118 <div class="add">
119 <Button
120 label="Add another value"
121 icon={html!(<Plus />)}
122 onclick={ctx.link().callback(move |_| InternalMessage::Add)}
123 />
124 </div>
125 </div>
126 </Modal>
127 )
128 }
129}