mirror of
				https://github.com/nitnelave/lldap.git
				synced 2023-04-12 14:25:13 +00:00 
			
		
		
		
	app: Extract a RemoveUserFromGroup component
This commit is contained in:
		
							parent
							
								
									14be1170f2
								
							
						
					
					
						commit
						00efdb42af
					
				
							
								
								
									
										16
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										16
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							@ -1770,6 +1770,7 @@ dependencies = [
 | 
				
			|||||||
 "yew-router",
 | 
					 "yew-router",
 | 
				
			||||||
 "yew_form",
 | 
					 "yew_form",
 | 
				
			||||||
 "yew_form_derive",
 | 
					 "yew_form_derive",
 | 
				
			||||||
 | 
					 "yewtil",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
@ -3537,6 +3538,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			|||||||
checksum = "8ce9b1b516211d33767048e5d47fa2a381ed8b76fc48d2ce4aa39877f9f183e0"
 | 
					checksum = "8ce9b1b516211d33767048e5d47fa2a381ed8b76fc48d2ce4aa39877f9f183e0"
 | 
				
			||||||
dependencies = [
 | 
					dependencies = [
 | 
				
			||||||
 "cfg-if 1.0.0",
 | 
					 "cfg-if 1.0.0",
 | 
				
			||||||
 | 
					 "serde",
 | 
				
			||||||
 | 
					 "serde_json",
 | 
				
			||||||
 "wasm-bindgen-macro",
 | 
					 "wasm-bindgen-macro",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -3757,6 +3760,19 @@ dependencies = [
 | 
				
			|||||||
 "yew_form",
 | 
					 "yew_form",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "yewtil"
 | 
				
			||||||
 | 
					version = "0.4.0"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "8543663ac49cd613df079282a1d8bdbdebdad6e02bac229f870fd4237b5d9aaa"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "log",
 | 
				
			||||||
 | 
					 "wasm-bindgen",
 | 
				
			||||||
 | 
					 "wasm-bindgen-futures",
 | 
				
			||||||
 | 
					 "web-sys",
 | 
				
			||||||
 | 
					 "yew",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "zeroize"
 | 
					name = "zeroize"
 | 
				
			||||||
version = "1.4.1"
 | 
					version = "1.4.1"
 | 
				
			||||||
 | 
				
			|||||||
@ -18,6 +18,7 @@ validator = "*"
 | 
				
			|||||||
validator_derive = "*"
 | 
					validator_derive = "*"
 | 
				
			||||||
wasm-bindgen = "0.2"
 | 
					wasm-bindgen = "0.2"
 | 
				
			||||||
yew = "0.18"
 | 
					yew = "0.18"
 | 
				
			||||||
 | 
					yewtil = "*"
 | 
				
			||||||
yew-router = "0.15"
 | 
					yew-router = "0.15"
 | 
				
			||||||
yew_form = "0.1.8"
 | 
					yew_form = "0.1.8"
 | 
				
			||||||
yew_form_derive = "*"
 | 
					yew_form_derive = "*"
 | 
				
			||||||
 | 
				
			|||||||
@ -1,7 +1,7 @@
 | 
				
			|||||||
use crate::{
 | 
					use crate::{
 | 
				
			||||||
    components::{
 | 
					    components::{
 | 
				
			||||||
        select::{Select, SelectOption, SelectOptionProps},
 | 
					        select::{Select, SelectOption, SelectOptionProps},
 | 
				
			||||||
        user_details::{Group, User},
 | 
					        user_details::Group,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    infra::api::HostService,
 | 
					    infra::api::HostService,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
@ -12,6 +12,7 @@ use yew::{
 | 
				
			|||||||
    prelude::*,
 | 
					    prelude::*,
 | 
				
			||||||
    services::{fetch::FetchTask, ConsoleService},
 | 
					    services::{fetch::FetchTask, ConsoleService},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					use yewtil::NeqAssign;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(GraphQLQuery)]
 | 
					#[derive(GraphQLQuery)]
 | 
				
			||||||
#[graphql(
 | 
					#[graphql(
 | 
				
			||||||
@ -63,7 +64,8 @@ pub enum Msg {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#[derive(yew::Properties, Clone, PartialEq)]
 | 
					#[derive(yew::Properties, Clone, PartialEq)]
 | 
				
			||||||
pub struct Props {
 | 
					pub struct Props {
 | 
				
			||||||
    pub user: User,
 | 
					    pub username: String,
 | 
				
			||||||
 | 
					    pub groups: Vec<Group>,
 | 
				
			||||||
    pub on_user_added_to_group: Callback<Group>,
 | 
					    pub on_user_added_to_group: Callback<Group>,
 | 
				
			||||||
    pub on_error: Callback<Error>,
 | 
					    pub on_error: Callback<Error>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -89,7 +91,7 @@ impl AddUserToGroupComponent {
 | 
				
			|||||||
        };
 | 
					        };
 | 
				
			||||||
        self._task = HostService::graphql_query::<AddUserToGroup>(
 | 
					        self._task = HostService::graphql_query::<AddUserToGroup>(
 | 
				
			||||||
            add_user_to_group::Variables {
 | 
					            add_user_to_group::Variables {
 | 
				
			||||||
                user: self.props.user.id.clone(),
 | 
					                user: self.props.username.clone(),
 | 
				
			||||||
                group: group_id,
 | 
					                group: group_id,
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            self.link.callback(Msg::AddGroupResponse),
 | 
					            self.link.callback(Msg::AddGroupResponse),
 | 
				
			||||||
@ -133,7 +135,7 @@ impl AddUserToGroupComponent {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn get_selectable_group_list(&self, group_list: &[Group]) -> Vec<Group> {
 | 
					    fn get_selectable_group_list(&self, group_list: &[Group]) -> Vec<Group> {
 | 
				
			||||||
        let user_groups = self.props.user.groups.iter().collect::<HashSet<_>>();
 | 
					        let user_groups = self.props.groups.iter().collect::<HashSet<_>>();
 | 
				
			||||||
        group_list
 | 
					        group_list
 | 
				
			||||||
            .iter()
 | 
					            .iter()
 | 
				
			||||||
            .filter(|g| !user_groups.contains(g))
 | 
					            .filter(|g| !user_groups.contains(g))
 | 
				
			||||||
@ -168,12 +170,7 @@ impl Component for AddUserToGroupComponent {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn change(&mut self, props: Self::Properties) -> ShouldRender {
 | 
					    fn change(&mut self, props: Self::Properties) -> ShouldRender {
 | 
				
			||||||
        if props.user.groups != self.props.user.groups {
 | 
					        self.props.neq_assign(props)
 | 
				
			||||||
            self.props.user = props.user;
 | 
					 | 
				
			||||||
            true
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            false
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn view(&self) -> Html {
 | 
					    fn view(&self) -> Html {
 | 
				
			||||||
 | 
				
			|||||||
@ -4,6 +4,7 @@ pub mod change_password;
 | 
				
			|||||||
pub mod create_user;
 | 
					pub mod create_user;
 | 
				
			||||||
pub mod login;
 | 
					pub mod login;
 | 
				
			||||||
pub mod logout;
 | 
					pub mod logout;
 | 
				
			||||||
 | 
					pub mod remove_user_from_group;
 | 
				
			||||||
pub mod router;
 | 
					pub mod router;
 | 
				
			||||||
pub mod select;
 | 
					pub mod select;
 | 
				
			||||||
pub mod user_details;
 | 
					pub mod user_details;
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										111
									
								
								app/src/components/remove_user_from_group.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										111
									
								
								app/src/components/remove_user_from_group.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,111 @@
 | 
				
			|||||||
 | 
					use crate::{components::user_details::Group, infra::api::HostService};
 | 
				
			||||||
 | 
					use anyhow::{Error, Result};
 | 
				
			||||||
 | 
					use graphql_client::GraphQLQuery;
 | 
				
			||||||
 | 
					use yew::{
 | 
				
			||||||
 | 
					    prelude::*,
 | 
				
			||||||
 | 
					    services::{fetch::FetchTask, ConsoleService},
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(GraphQLQuery)]
 | 
				
			||||||
 | 
					#[graphql(
 | 
				
			||||||
 | 
					    schema_path = "../schema.graphql",
 | 
				
			||||||
 | 
					    query_path = "queries/remove_user_from_group.graphql",
 | 
				
			||||||
 | 
					    response_derives = "Debug",
 | 
				
			||||||
 | 
					    variables_derives = "Clone",
 | 
				
			||||||
 | 
					    custom_scalars_module = "crate::infra::graphql"
 | 
				
			||||||
 | 
					)]
 | 
				
			||||||
 | 
					pub struct RemoveUserFromGroup;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub struct RemoveUserFromGroupComponent {
 | 
				
			||||||
 | 
					    link: ComponentLink<Self>,
 | 
				
			||||||
 | 
					    props: Props,
 | 
				
			||||||
 | 
					    // Used to keep the request alive long enough.
 | 
				
			||||||
 | 
					    _task: Option<FetchTask>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(yew::Properties, Clone, PartialEq)]
 | 
				
			||||||
 | 
					pub struct Props {
 | 
				
			||||||
 | 
					    pub username: String,
 | 
				
			||||||
 | 
					    pub group: Group,
 | 
				
			||||||
 | 
					    pub is_admin: bool,
 | 
				
			||||||
 | 
					    pub on_user_removed_from_group: Callback<Group>,
 | 
				
			||||||
 | 
					    pub on_error: Callback<Error>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub enum Msg {
 | 
				
			||||||
 | 
					    SubmitRemoveGroup,
 | 
				
			||||||
 | 
					    RemoveGroupResponse(Result<remove_user_from_group::ResponseData>),
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl RemoveUserFromGroupComponent {
 | 
				
			||||||
 | 
					    fn submit_remove_group(&mut self) -> Result<bool> {
 | 
				
			||||||
 | 
					        let group = self.props.group.id;
 | 
				
			||||||
 | 
					        self._task = HostService::graphql_query::<RemoveUserFromGroup>(
 | 
				
			||||||
 | 
					            remove_user_from_group::Variables {
 | 
				
			||||||
 | 
					                user: self.props.username.clone(),
 | 
				
			||||||
 | 
					                group,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            self.link.callback(Msg::RemoveGroupResponse),
 | 
				
			||||||
 | 
					            "Error trying to initiate removing the user from a group",
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        .map_err(|e| {
 | 
				
			||||||
 | 
					            ConsoleService::log(&e.to_string());
 | 
				
			||||||
 | 
					            e
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					        .ok();
 | 
				
			||||||
 | 
					        Ok(true)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn handle_msg(&mut self, msg: <Self as Component>::Message) -> Result<bool> {
 | 
				
			||||||
 | 
					        match msg {
 | 
				
			||||||
 | 
					            Msg::SubmitRemoveGroup => return self.submit_remove_group(),
 | 
				
			||||||
 | 
					            Msg::RemoveGroupResponse(response) => {
 | 
				
			||||||
 | 
					                response?;
 | 
				
			||||||
 | 
					                self.props
 | 
				
			||||||
 | 
					                    .on_user_removed_from_group
 | 
				
			||||||
 | 
					                    .emit(self.props.group.clone());
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        Ok(true)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Component for RemoveUserFromGroupComponent {
 | 
				
			||||||
 | 
					    type Message = Msg;
 | 
				
			||||||
 | 
					    type Properties = Props;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {
 | 
				
			||||||
 | 
					        Self {
 | 
				
			||||||
 | 
					            link,
 | 
				
			||||||
 | 
					            props,
 | 
				
			||||||
 | 
					            _task: None,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn update(&mut self, msg: Self::Message) -> ShouldRender {
 | 
				
			||||||
 | 
					        match self.handle_msg(msg) {
 | 
				
			||||||
 | 
					            Err(e) => {
 | 
				
			||||||
 | 
					                self.props.on_error.emit(e);
 | 
				
			||||||
 | 
					                true
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            Ok(b) => b,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn change(&mut self, _: Self::Properties) -> ShouldRender {
 | 
				
			||||||
 | 
					        false
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn view(&self) -> Html {
 | 
				
			||||||
 | 
					        let group = &self.props.group;
 | 
				
			||||||
 | 
					        html! {
 | 
				
			||||||
 | 
					          <>
 | 
				
			||||||
 | 
					            <td>{&group.display_name}</td>
 | 
				
			||||||
 | 
					            { if self.props.is_admin { html! {
 | 
				
			||||||
 | 
					                <td><button onclick=self.link.callback(|_| Msg::SubmitRemoveGroup)>{"-"}</button></td>
 | 
				
			||||||
 | 
					              }} else { html!{} }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          </>
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -1,8 +1,10 @@
 | 
				
			|||||||
use yew::{html::ChangeData, prelude::*};
 | 
					use yew::{html::ChangeData, prelude::*};
 | 
				
			||||||
 | 
					use yewtil::NeqAssign;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub struct Select {
 | 
					pub struct Select {
 | 
				
			||||||
    link: ComponentLink<Self>,
 | 
					    link: ComponentLink<Self>,
 | 
				
			||||||
    props: SelectProps,
 | 
					    props: SelectProps,
 | 
				
			||||||
 | 
					    node_ref: NodeRef,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(yew::Properties, Clone, PartialEq, Debug)]
 | 
					#[derive(yew::Properties, Clone, PartialEq, Debug)]
 | 
				
			||||||
@ -26,48 +28,47 @@ impl Select {
 | 
				
			|||||||
            .nth(nth as usize)
 | 
					            .nth(nth as usize)
 | 
				
			||||||
            .map(|child| child.props)
 | 
					            .map(|child| child.props)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn send_selection_update(&self) {
 | 
				
			||||||
 | 
					        let select_node = self.node_ref.cast::<web_sys::HtmlSelectElement>().unwrap();
 | 
				
			||||||
 | 
					        self.props
 | 
				
			||||||
 | 
					            .on_selection_change
 | 
				
			||||||
 | 
					            .emit(self.get_nth_child_props(select_node.selected_index()))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Component for Select {
 | 
					impl Component for Select {
 | 
				
			||||||
    type Message = SelectMsg;
 | 
					    type Message = SelectMsg;
 | 
				
			||||||
    type Properties = SelectProps;
 | 
					    type Properties = SelectProps;
 | 
				
			||||||
    fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {
 | 
					    fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {
 | 
				
			||||||
        let res = Self { link, props };
 | 
					        Self {
 | 
				
			||||||
        res.props
 | 
					            link,
 | 
				
			||||||
            .on_selection_change
 | 
					            props,
 | 
				
			||||||
            .emit(res.get_nth_child_props(0));
 | 
					            node_ref: NodeRef::default(),
 | 
				
			||||||
        res
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn rendered(&mut self, _first_render: bool) {
 | 
				
			||||||
 | 
					        self.send_selection_update();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn update(&mut self, msg: Self::Message) -> ShouldRender {
 | 
					    fn update(&mut self, msg: Self::Message) -> ShouldRender {
 | 
				
			||||||
        match msg {
 | 
					        let SelectMsg::OnSelectChange(data) = msg;
 | 
				
			||||||
            SelectMsg::OnSelectChange(data) => match data {
 | 
					        match data {
 | 
				
			||||||
                ChangeData::Select(e) => {
 | 
					            ChangeData::Select(_) => self.send_selection_update(),
 | 
				
			||||||
                    self.props
 | 
					 | 
				
			||||||
                        .on_selection_change
 | 
					 | 
				
			||||||
                        .emit(self.get_nth_child_props(e.selected_index()));
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            _ => unreachable!(),
 | 
					            _ => unreachable!(),
 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        false
 | 
					        false
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn change(&mut self, props: Self::Properties) -> ShouldRender {
 | 
					    fn change(&mut self, props: Self::Properties) -> ShouldRender {
 | 
				
			||||||
        if self.props.children.len() != props.children.len() {
 | 
					        self.props.children.neq_assign(props.children)
 | 
				
			||||||
            let was_empty = self.props.children.is_empty();
 | 
					 | 
				
			||||||
            self.props = props;
 | 
					 | 
				
			||||||
            if self.props.children.is_empty() || was_empty {
 | 
					 | 
				
			||||||
                self.props
 | 
					 | 
				
			||||||
                    .on_selection_change
 | 
					 | 
				
			||||||
                    .emit(self.get_nth_child_props(0));
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            true
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            false
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn view(&self) -> Html {
 | 
					    fn view(&self) -> Html {
 | 
				
			||||||
        html! {
 | 
					        html! {
 | 
				
			||||||
            <select
 | 
					            <select
 | 
				
			||||||
 | 
					              ref=self.node_ref.clone()
 | 
				
			||||||
              onchange=self.link.callback(SelectMsg::OnSelectChange)>
 | 
					              onchange=self.link.callback(SelectMsg::OnSelectChange)>
 | 
				
			||||||
            { self.props.children.clone() }
 | 
					            { self.props.children.clone() }
 | 
				
			||||||
            </select>
 | 
					            </select>
 | 
				
			||||||
@ -79,7 +80,7 @@ pub struct SelectOption {
 | 
				
			|||||||
    props: SelectOptionProps,
 | 
					    props: SelectOptionProps,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(yew::Properties, Clone, PartialEq)]
 | 
					#[derive(yew::Properties, Clone, PartialEq, Debug)]
 | 
				
			||||||
pub struct SelectOptionProps {
 | 
					pub struct SelectOptionProps {
 | 
				
			||||||
    pub value: String,
 | 
					    pub value: String,
 | 
				
			||||||
    pub text: String,
 | 
					    pub text: String,
 | 
				
			||||||
@ -88,20 +89,19 @@ pub struct SelectOptionProps {
 | 
				
			|||||||
impl Component for SelectOption {
 | 
					impl Component for SelectOption {
 | 
				
			||||||
    type Message = ();
 | 
					    type Message = ();
 | 
				
			||||||
    type Properties = SelectOptionProps;
 | 
					    type Properties = SelectOptionProps;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn create(props: Self::Properties, _: ComponentLink<Self>) -> Self {
 | 
					    fn create(props: Self::Properties, _: ComponentLink<Self>) -> Self {
 | 
				
			||||||
        Self { props }
 | 
					        Self { props }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn update(&mut self, _: Self::Message) -> ShouldRender {
 | 
					    fn update(&mut self, _: Self::Message) -> ShouldRender {
 | 
				
			||||||
        false
 | 
					        false
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn change(&mut self, props: Self::Properties) -> ShouldRender {
 | 
					    fn change(&mut self, props: Self::Properties) -> ShouldRender {
 | 
				
			||||||
        if self.props != props {
 | 
					        self.props.neq_assign(props)
 | 
				
			||||||
            self.props = props;
 | 
					 | 
				
			||||||
            true
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            false
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn view(&self) -> Html {
 | 
					    fn view(&self) -> Html {
 | 
				
			||||||
        html! {
 | 
					        html! {
 | 
				
			||||||
          <option value=self.props.value.clone()>
 | 
					          <option value=self.props.value.clone()>
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,7 @@
 | 
				
			|||||||
use crate::{
 | 
					use crate::{
 | 
				
			||||||
    components::{
 | 
					    components::{
 | 
				
			||||||
        add_user_to_group::AddUserToGroupComponent,
 | 
					        add_user_to_group::AddUserToGroupComponent,
 | 
				
			||||||
 | 
					        remove_user_from_group::RemoveUserFromGroupComponent,
 | 
				
			||||||
        router::{AppRoute, NavButton},
 | 
					        router::{AppRoute, NavButton},
 | 
				
			||||||
        user_details_form::UserDetailsForm,
 | 
					        user_details_form::UserDetailsForm,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
@ -25,30 +26,14 @@ pub struct GetUserDetails;
 | 
				
			|||||||
pub type User = get_user_details::GetUserDetailsUser;
 | 
					pub type User = get_user_details::GetUserDetailsUser;
 | 
				
			||||||
pub type Group = get_user_details::GetUserDetailsUserGroups;
 | 
					pub type Group = get_user_details::GetUserDetailsUserGroups;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(GraphQLQuery)]
 | 
					 | 
				
			||||||
#[graphql(
 | 
					 | 
				
			||||||
    schema_path = "../schema.graphql",
 | 
					 | 
				
			||||||
    query_path = "queries/remove_user_from_group.graphql",
 | 
					 | 
				
			||||||
    response_derives = "Debug",
 | 
					 | 
				
			||||||
    variables_derives = "Clone",
 | 
					 | 
				
			||||||
    custom_scalars_module = "crate::infra::graphql"
 | 
					 | 
				
			||||||
)]
 | 
					 | 
				
			||||||
pub struct RemoveUserFromGroup;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub struct UserDetails {
 | 
					pub struct UserDetails {
 | 
				
			||||||
    link: ComponentLink<Self>,
 | 
					    link: ComponentLink<Self>,
 | 
				
			||||||
    /// Which user this is about.
 | 
					    props: Props,
 | 
				
			||||||
    username: String,
 | 
					 | 
				
			||||||
    /// The user info. If none, the error is in `error`. If `error` is None, then we haven't
 | 
					    /// The user info. If none, the error is in `error`. If `error` is None, then we haven't
 | 
				
			||||||
    /// received the server response yet.
 | 
					    /// received the server response yet.
 | 
				
			||||||
    user: Option<User>,
 | 
					    user: Option<User>,
 | 
				
			||||||
    /// Error message displayed to the user.
 | 
					    /// Error message displayed to the user.
 | 
				
			||||||
    error: Option<Error>,
 | 
					    error: Option<Error>,
 | 
				
			||||||
    /// True iff we just finished updating the user, to display a successful message.
 | 
					 | 
				
			||||||
    update_successful: bool,
 | 
					 | 
				
			||||||
    is_admin: bool,
 | 
					 | 
				
			||||||
    /// The group that we're requesting to remove, if any.
 | 
					 | 
				
			||||||
    group_to_remove: Option<Group>,
 | 
					 | 
				
			||||||
    // Used to keep the request alive long enough.
 | 
					    // Used to keep the request alive long enough.
 | 
				
			||||||
    _task: Option<FetchTask>,
 | 
					    _task: Option<FetchTask>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -58,10 +43,9 @@ pub struct UserDetails {
 | 
				
			|||||||
pub enum Msg {
 | 
					pub enum Msg {
 | 
				
			||||||
    /// Received the user details response, either the user data or an error.
 | 
					    /// Received the user details response, either the user data or an error.
 | 
				
			||||||
    UserDetailsResponse(Result<get_user_details::ResponseData>),
 | 
					    UserDetailsResponse(Result<get_user_details::ResponseData>),
 | 
				
			||||||
    SubmitRemoveGroup(Group),
 | 
					 | 
				
			||||||
    RemoveGroupResponse(Result<remove_user_from_group::ResponseData>),
 | 
					 | 
				
			||||||
    OnError(Error),
 | 
					    OnError(Error),
 | 
				
			||||||
    OnUserAddedToGroup(Group),
 | 
					    OnUserAddedToGroup(Group),
 | 
				
			||||||
 | 
					    OnUserRemovedFromGroup(Group),
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(yew::Properties, Clone, PartialEq)]
 | 
					#[derive(yew::Properties, Clone, PartialEq)]
 | 
				
			||||||
@ -74,7 +58,7 @@ impl UserDetails {
 | 
				
			|||||||
    fn get_user_details(&mut self) {
 | 
					    fn get_user_details(&mut self) {
 | 
				
			||||||
        self._task = HostService::graphql_query::<GetUserDetails>(
 | 
					        self._task = HostService::graphql_query::<GetUserDetails>(
 | 
				
			||||||
            get_user_details::Variables {
 | 
					            get_user_details::Variables {
 | 
				
			||||||
                id: self.username.clone(),
 | 
					                id: self.props.username.clone(),
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            self.link.callback(Msg::UserDetailsResponse),
 | 
					            self.link.callback(Msg::UserDetailsResponse),
 | 
				
			||||||
            "Error trying to fetch user details",
 | 
					            "Error trying to fetch user details",
 | 
				
			||||||
@ -86,26 +70,7 @@ impl UserDetails {
 | 
				
			|||||||
        .ok();
 | 
					        .ok();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn submit_remove_group(&mut self, group: Group) -> Result<bool> {
 | 
					 | 
				
			||||||
        self._task = HostService::graphql_query::<RemoveUserFromGroup>(
 | 
					 | 
				
			||||||
            remove_user_from_group::Variables {
 | 
					 | 
				
			||||||
                user: self.username.clone(),
 | 
					 | 
				
			||||||
                group: group.id,
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            self.link.callback(Msg::RemoveGroupResponse),
 | 
					 | 
				
			||||||
            "Error trying to initiate removing the user from a group",
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
        .map_err(|e| {
 | 
					 | 
				
			||||||
            ConsoleService::log(&e.to_string());
 | 
					 | 
				
			||||||
            e
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
        .ok();
 | 
					 | 
				
			||||||
        self.group_to_remove = Some(group);
 | 
					 | 
				
			||||||
        Ok(true)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn handle_msg(&mut self, msg: <Self as Component>::Message) -> Result<bool> {
 | 
					    fn handle_msg(&mut self, msg: <Self as Component>::Message) -> Result<bool> {
 | 
				
			||||||
        self.update_successful = false;
 | 
					 | 
				
			||||||
        match msg {
 | 
					        match msg {
 | 
				
			||||||
            Msg::UserDetailsResponse(response) => match response {
 | 
					            Msg::UserDetailsResponse(response) => match response {
 | 
				
			||||||
                Ok(user) => self.user = Some(user.user),
 | 
					                Ok(user) => self.user = Some(user.user),
 | 
				
			||||||
@ -114,27 +79,19 @@ impl UserDetails {
 | 
				
			|||||||
                    bail!("Error getting user details: {}", e);
 | 
					                    bail!("Error getting user details: {}", e);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            Msg::SubmitRemoveGroup(group) => return self.submit_remove_group(group),
 | 
					 | 
				
			||||||
            Msg::RemoveGroupResponse(response) => {
 | 
					 | 
				
			||||||
                response?;
 | 
					 | 
				
			||||||
                let group = self.group_to_remove.take().unwrap();
 | 
					 | 
				
			||||||
                // Remove the group from the user and add it to the dropdown.
 | 
					 | 
				
			||||||
                self.user.as_mut().unwrap().groups.retain(|g| g != &group);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            Msg::OnError(e) => return Err(e),
 | 
					            Msg::OnError(e) => return Err(e),
 | 
				
			||||||
            Msg::OnUserAddedToGroup(group) => {
 | 
					            Msg::OnUserAddedToGroup(group) => {
 | 
				
			||||||
                self.user.as_mut().unwrap().groups.push(group);
 | 
					                self.user.as_mut().unwrap().groups.push(group);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					            Msg::OnUserRemovedFromGroup(group) => {
 | 
				
			||||||
 | 
					                self.user.as_mut().unwrap().groups.retain(|g| g != &group);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        Ok(true)
 | 
					        Ok(true)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn view_messages(&self, error: &Option<Error>) -> Html {
 | 
					    fn view_messages(&self, error: &Option<Error>) -> Html {
 | 
				
			||||||
        if self.update_successful {
 | 
					        if let Some(e) = error {
 | 
				
			||||||
            html! {
 | 
					 | 
				
			||||||
              <span>{"Update successful!"}</span>
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        } else if let Some(e) = error {
 | 
					 | 
				
			||||||
            html! {
 | 
					            html! {
 | 
				
			||||||
              <div>
 | 
					              <div>
 | 
				
			||||||
                <span>{"Error: "}{e.to_string()}</span>
 | 
					                <span>{"Error: "}{e.to_string()}</span>
 | 
				
			||||||
@ -147,15 +104,15 @@ impl UserDetails {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    fn view_group_memberships(&self, u: &User) -> Html {
 | 
					    fn view_group_memberships(&self, u: &User) -> Html {
 | 
				
			||||||
        let make_group_row = |group: &Group| {
 | 
					        let make_group_row = |group: &Group| {
 | 
				
			||||||
            let id = group.id;
 | 
					 | 
				
			||||||
            let display_name = group.display_name.clone();
 | 
					            let display_name = group.display_name.clone();
 | 
				
			||||||
            html! {
 | 
					            html! {
 | 
				
			||||||
              <tr key="groupRow_".to_string() + &display_name>
 | 
					              <tr key="groupRow_".to_string() + &display_name>
 | 
				
			||||||
                <td>{&group.display_name}</td>
 | 
					                <RemoveUserFromGroupComponent
 | 
				
			||||||
                { if self.is_admin { html! {
 | 
					                  username=u.id.clone()
 | 
				
			||||||
                    <td><button onclick=self.link.callback(move |_| Msg::SubmitRemoveGroup(Group{id, display_name: display_name.clone()}))>{"-"}</button></td>
 | 
					                  group=group.clone()
 | 
				
			||||||
                  }} else { html!{} }
 | 
					                  is_admin=self.props.is_admin
 | 
				
			||||||
                }
 | 
					                  on_user_removed_from_group=self.link.callback(Msg::OnUserRemovedFromGroup)
 | 
				
			||||||
 | 
					                  on_error=self.link.callback(Msg::OnError)/>
 | 
				
			||||||
              </tr>
 | 
					              </tr>
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
@ -165,7 +122,7 @@ impl UserDetails {
 | 
				
			|||||||
          <table>
 | 
					          <table>
 | 
				
			||||||
            <tr key="headerRow">
 | 
					            <tr key="headerRow">
 | 
				
			||||||
              <th>{"Group"}</th>
 | 
					              <th>{"Group"}</th>
 | 
				
			||||||
              { if self.is_admin { html!{ <th></th> }} else { html!{} }}
 | 
					              { if self.props.is_admin { html!{ <th></th> }} else { html!{} }}
 | 
				
			||||||
            </tr>
 | 
					            </tr>
 | 
				
			||||||
            {u.groups.iter().map(make_group_row).collect::<Vec<_>>()}
 | 
					            {u.groups.iter().map(make_group_row).collect::<Vec<_>>()}
 | 
				
			||||||
            <tr key="groupToAddRow">
 | 
					            <tr key="groupToAddRow">
 | 
				
			||||||
@ -177,10 +134,11 @@ impl UserDetails {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn view_add_group_button(&self, u: &User) -> Html {
 | 
					    fn view_add_group_button(&self, u: &User) -> Html {
 | 
				
			||||||
        if self.is_admin {
 | 
					        if self.props.is_admin {
 | 
				
			||||||
            html! {
 | 
					            html! {
 | 
				
			||||||
                <AddUserToGroupComponent
 | 
					                <AddUserToGroupComponent
 | 
				
			||||||
                    user=u.clone()
 | 
					                    username=u.id.clone()
 | 
				
			||||||
 | 
					                    groups=u.groups.clone()
 | 
				
			||||||
                    on_error=self.link.callback(Msg::OnError)
 | 
					                    on_error=self.link.callback(Msg::OnError)
 | 
				
			||||||
                    on_user_added_to_group=self.link.callback(Msg::OnUserAddedToGroup)/>
 | 
					                    on_user_added_to_group=self.link.callback(Msg::OnUserAddedToGroup)/>
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@ -197,13 +155,10 @@ impl Component for UserDetails {
 | 
				
			|||||||
    fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {
 | 
					    fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {
 | 
				
			||||||
        let mut table = Self {
 | 
					        let mut table = Self {
 | 
				
			||||||
            link,
 | 
					            link,
 | 
				
			||||||
            username: props.username,
 | 
					            props,
 | 
				
			||||||
            _task: None,
 | 
					            _task: None,
 | 
				
			||||||
            user: None,
 | 
					            user: None,
 | 
				
			||||||
            error: None,
 | 
					            error: None,
 | 
				
			||||||
            update_successful: false,
 | 
					 | 
				
			||||||
            is_admin: props.is_admin,
 | 
					 | 
				
			||||||
            group_to_remove: None,
 | 
					 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
        table.get_user_details();
 | 
					        table.get_user_details();
 | 
				
			||||||
        table
 | 
					        table
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user