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