From 1e5b47ce7d77fb997aac859aed31c138e44a18e0 Mon Sep 17 00:00:00 2001 From: Valentin Tolmer Date: Fri, 17 Sep 2021 21:27:00 +0200 Subject: [PATCH] app: Extract a Select component --- app/src/components/add_user_to_group.rs | 118 +++++++----------------- app/src/components/mod.rs | 1 + app/src/components/select.rs | 112 ++++++++++++++++++++++ app/src/components/user_details.rs | 2 +- 4 files changed, 146 insertions(+), 87 deletions(-) create mode 100644 app/src/components/select.rs diff --git a/app/src/components/add_user_to_group.rs b/app/src/components/add_user_to_group.rs index 117ce67..b805cc2 100644 --- a/app/src/components/add_user_to_group.rs +++ b/app/src/components/add_user_to_group.rs @@ -1,12 +1,14 @@ use crate::{ - components::user_details::{Group, User}, + components::{ + select::{Select, SelectOption, SelectOptionProps}, + user_details::{Group, User}, + }, infra::api::HostService, }; use anyhow::{Error, Result}; use graphql_client::GraphQLQuery; use std::collections::HashSet; use yew::{ - html::ChangeData, prelude::*, services::{fetch::FetchTask, ConsoleService}, }; @@ -43,24 +45,20 @@ impl From for Group { pub struct AddUserToGroupComponent { link: ComponentLink, - user: User, + props: Props, /// The list of existing groups, initially not loaded. group_list: Option>, - /// Whether the "+" button has been clicked. - add_group: bool, - on_error: Callback, - on_user_added_to_group: Callback, + /// The currently selected group. selected_group: Option, // Used to keep the request alive long enough. _task: Option, } pub enum Msg { - AddGroupButtonClicked, GroupListResponse(Result), SubmitAddGroup, AddGroupResponse(Result), - SelectionChanged(ChangeData), + SelectionChanged(Option), } #[derive(yew::Properties, Clone, PartialEq)] @@ -91,7 +89,7 @@ impl AddUserToGroupComponent { }; self._task = HostService::graphql_query::( add_user_to_group::Variables { - user: self.user.id.clone(), + user: self.props.user.id.clone(), group: group_id, }, self.link.callback(Msg::AddGroupResponse), @@ -107,97 +105,62 @@ impl AddUserToGroupComponent { fn handle_msg(&mut self, msg: ::Message) -> Result { match msg { - Msg::AddGroupButtonClicked => { - if self.group_list.is_none() { - self.get_group_list(); - } else { - self.set_default_selection(); - } - self.add_group = true; - } Msg::GroupListResponse(response) => { self.group_list = Some(response?.groups.into_iter().map(Into::into).collect()); - self.set_default_selection(); } Msg::SubmitAddGroup => return self.submit_add_group(), Msg::AddGroupResponse(response) => { response?; // Adding the user to the group succeeded, we're not in the process of adding a // group anymore. - self.add_group = false; let group = self .selected_group .as_ref() .expect("Could not get selected group") .clone(); // Remove the group from the dropdown. - self.on_user_added_to_group.emit(group); + self.props.on_user_added_to_group.emit(group); + } + Msg::SelectionChanged(option_props) => { + self.selected_group = option_props.map(|props| Group { + id: props.value.parse::().unwrap(), + display_name: props.text, + }); + return Ok(false); } - Msg::SelectionChanged(data) => match data { - ChangeData::Select(e) => { - self.update_selection(e); - } - _ => unreachable!(), - }, } Ok(true) } - fn update_selection(&mut self, e: web_sys::HtmlSelectElement) { - if e.selected_index() == -1 { - self.selected_group = None; - } else { - use wasm_bindgen::JsCast; - let option = e - .options() - .get_with_index(e.selected_index() as u32) - .unwrap() - .dyn_into::() - .unwrap(); - self.selected_group = Some(Group { - id: option.value().parse::().unwrap(), - display_name: option.text(), - }); - } - } - - fn get_selectable_group_list(&self, group_list: &Vec) -> Vec { - let user_groups = self.user.groups.iter().collect::>(); + fn get_selectable_group_list(&self, group_list: &[Group]) -> Vec { + let user_groups = self.props.user.groups.iter().collect::>(); group_list .iter() .filter(|g| !user_groups.contains(g)) .map(Clone::clone) .collect() } - - fn set_default_selection(&mut self) { - self.selected_group = (|| { - let groups = self.get_selectable_group_list(self.group_list.as_ref()?); - groups.into_iter().next() - })(); - } } impl Component for AddUserToGroupComponent { type Message = Msg; type Properties = Props; fn create(props: Self::Properties, link: ComponentLink) -> Self { - Self { + let mut res = Self { link, - user: props.user, + props, group_list: None, - add_group: false, - on_error: props.on_error, - on_user_added_to_group: props.on_user_added_to_group, selected_group: None, _task: None, - } + }; + res.get_group_list(); + res } fn update(&mut self, msg: Self::Message) -> ShouldRender { match self.handle_msg(msg) { Err(e) => { ConsoleService::error(&e.to_string()); - self.on_error.emit(e); + self.props.on_error.emit(e); true } Ok(b) => b, @@ -205,11 +168,8 @@ impl Component for AddUserToGroupComponent { } fn change(&mut self, props: Self::Properties) -> ShouldRender { - if props.user.groups != self.user.groups { - self.user = props.user; - if self.selected_group.is_none() { - self.set_default_selection(); - } + if props.user.groups != self.props.user.groups { + self.props.user = props.user; true } else { false @@ -217,39 +177,25 @@ impl Component for AddUserToGroupComponent { } fn view(&self) -> Html { - if !self.add_group { - return html! { - <> - - - - - - }; - } - if let Some(group_list) = &self.group_list { - let to_add_group_list = self.get_selectable_group_list(&group_list); + let to_add_group_list = self.get_selectable_group_list(group_list); + #[allow(unused_braces)] let make_select_option = |group: Group| { - html! { - + html_nested! { + } }; html! { <> - { to_add_group_list .into_iter() .map(make_select_option) .collect::>() } - +