mirror of
				https://github.com/nitnelave/lldap.git
				synced 2023-04-12 14:25:13 +00:00 
			
		
		
		
	Merge 9015c3068a into 18d9dd6ff9
				
					
				
			This commit is contained in:
		
						commit
						b7a522e07a
					
				
							
								
								
									
										12
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										12
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							@ -2404,7 +2404,7 @@ dependencies = [
 | 
				
			|||||||
 "tracing-forest",
 | 
					 "tracing-forest",
 | 
				
			||||||
 "tracing-log",
 | 
					 "tracing-log",
 | 
				
			||||||
 "tracing-subscriber",
 | 
					 "tracing-subscriber",
 | 
				
			||||||
 "uuid 0.8.2",
 | 
					 "uuid 1.3.0",
 | 
				
			||||||
 "webpki-roots",
 | 
					 "webpki-roots",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -2530,12 +2530,6 @@ dependencies = [
 | 
				
			|||||||
 "digest 0.10.6",
 | 
					 "digest 0.10.6",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					 | 
				
			||||||
name = "md5"
 | 
					 | 
				
			||||||
version = "0.7.0"
 | 
					 | 
				
			||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					 | 
				
			||||||
checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "memchr"
 | 
					name = "memchr"
 | 
				
			||||||
version = "2.5.0"
 | 
					version = "2.5.0"
 | 
				
			||||||
@ -4404,9 +4398,6 @@ name = "uuid"
 | 
				
			|||||||
version = "0.8.2"
 | 
					version = "0.8.2"
 | 
				
			||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"
 | 
					checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"
 | 
				
			||||||
dependencies = [
 | 
					 | 
				
			||||||
 "md5",
 | 
					 | 
				
			||||||
]
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "uuid"
 | 
					name = "uuid"
 | 
				
			||||||
@ -4415,6 +4406,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			|||||||
checksum = "1674845326ee10d37ca60470760d4288a6f80f304007d92e5c53bab78c9cfd79"
 | 
					checksum = "1674845326ee10d37ca60470760d4288a6f80f304007d92e5c53bab78c9cfd79"
 | 
				
			||||||
dependencies = [
 | 
					dependencies = [
 | 
				
			||||||
 "getrandom 0.2.8",
 | 
					 "getrandom 0.2.8",
 | 
				
			||||||
 | 
					 "md-5",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										6
									
								
								app/queries/get_user_avatar.graphql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								app/queries/get_user_avatar.graphql
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,6 @@
 | 
				
			|||||||
 | 
					query GetUserAvatar($id: String!) {
 | 
				
			||||||
 | 
					  user(userId: $id) {
 | 
				
			||||||
 | 
					    id
 | 
				
			||||||
 | 
					    avatar
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -1,5 +1,7 @@
 | 
				
			|||||||
use crate::{
 | 
					use crate::{
 | 
				
			||||||
    components::{
 | 
					    components::{
 | 
				
			||||||
 | 
					        avatar::ShowAvatar,
 | 
				
			||||||
 | 
					        avatar_cache::*,
 | 
				
			||||||
        change_password::ChangePasswordForm,
 | 
					        change_password::ChangePasswordForm,
 | 
				
			||||||
        create_group::CreateGroupForm,
 | 
					        create_group::CreateGroupForm,
 | 
				
			||||||
        create_user::CreateUserForm,
 | 
					        create_user::CreateUserForm,
 | 
				
			||||||
@ -136,8 +138,19 @@ impl Component for App {
 | 
				
			|||||||
        let link = ctx.link().clone();
 | 
					        let link = ctx.link().clone();
 | 
				
			||||||
        let is_admin = self.is_admin();
 | 
					        let is_admin = self.is_admin();
 | 
				
			||||||
        let password_reset_enabled = self.password_reset_enabled;
 | 
					        let password_reset_enabled = self.password_reset_enabled;
 | 
				
			||||||
 | 
					        let mode = self
 | 
				
			||||||
 | 
					            .user_info
 | 
				
			||||||
 | 
					            .clone()
 | 
				
			||||||
 | 
					            .map(|(username, is_admin)| {
 | 
				
			||||||
 | 
					                if is_admin {
 | 
				
			||||||
 | 
					                    CacheMode::AllUsers
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    CacheMode::SingleUser(username)
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .unwrap_or(CacheMode::None);
 | 
				
			||||||
        html! {
 | 
					        html! {
 | 
				
			||||||
          <div>
 | 
					          <AvatarCacheProvider {mode}>
 | 
				
			||||||
            {self.view_banner(ctx)}
 | 
					            {self.view_banner(ctx)}
 | 
				
			||||||
            <div class="container py-3 bg-kug">
 | 
					            <div class="container py-3 bg-kug">
 | 
				
			||||||
              <div class="row justify-content-center" style="padding-bottom: 80px;">
 | 
					              <div class="row justify-content-center" style="padding-bottom: 80px;">
 | 
				
			||||||
@ -149,7 +162,7 @@ impl Component for App {
 | 
				
			|||||||
              </div>
 | 
					              </div>
 | 
				
			||||||
              {self.view_footer()}
 | 
					              {self.view_footer()}
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
          </div>
 | 
					          </AvatarCacheProvider>
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -312,15 +325,7 @@ impl App {
 | 
				
			|||||||
                  id="dropdownUser"
 | 
					                  id="dropdownUser"
 | 
				
			||||||
                  data-bs-toggle="dropdown"
 | 
					                  data-bs-toggle="dropdown"
 | 
				
			||||||
                  aria-expanded="false">
 | 
					                  aria-expanded="false">
 | 
				
			||||||
                  <svg xmlns="http://www.w3.org/2000/svg"
 | 
					                  <ShowAvatar username={user_id.clone()} width=32 height=32 />
 | 
				
			||||||
                    width="32"
 | 
					 | 
				
			||||||
                    height="32"
 | 
					 | 
				
			||||||
                    fill="currentColor"
 | 
					 | 
				
			||||||
                    class="bi bi-person-circle"
 | 
					 | 
				
			||||||
                    viewBox="0 0 16 16">
 | 
					 | 
				
			||||||
                    <path d="M11 6a3 3 0 1 1-6 0 3 3 0 0 1 6 0z"/>
 | 
					 | 
				
			||||||
                    <path fill-rule="evenodd" d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8zm8-7a7 7 0 0 0-5.468 11.37C3.242 11.226 4.805 10 8 10s4.757 1.225 5.468 2.37A7 7 0 0 0 8 1z"/>
 | 
					 | 
				
			||||||
                  </svg>
 | 
					 | 
				
			||||||
                  <span class="ms-2">
 | 
					                  <span class="ms-2">
 | 
				
			||||||
                    {user_id}
 | 
					                    {user_id}
 | 
				
			||||||
                  </span>
 | 
					                  </span>
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										39
									
								
								app/src/components/avatar.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								app/src/components/avatar.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,39 @@
 | 
				
			|||||||
 | 
					use crate::components::avatar_cache::AvatarCacheContext;
 | 
				
			||||||
 | 
					use yew::{function_component, prelude::*};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Properties, PartialEq)]
 | 
				
			||||||
 | 
					pub struct Props {
 | 
				
			||||||
 | 
					    pub username: String,
 | 
				
			||||||
 | 
					    pub width: i32,
 | 
				
			||||||
 | 
					    pub height: i32,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[function_component(ShowAvatar)]
 | 
				
			||||||
 | 
					pub fn show_avatar(props: &Props) -> Html {
 | 
				
			||||||
 | 
					    let cache = use_context::<AvatarCacheContext>().expect("no ctx found");
 | 
				
			||||||
 | 
					    let avatar = cache
 | 
				
			||||||
 | 
					        .avatars
 | 
				
			||||||
 | 
					        .get(&props.username)
 | 
				
			||||||
 | 
					        .map(|val| val.clone())
 | 
				
			||||||
 | 
					        .unwrap_or(None);
 | 
				
			||||||
 | 
					    match avatar {
 | 
				
			||||||
 | 
					        Some(avatar) => html! {
 | 
				
			||||||
 | 
					            <img
 | 
				
			||||||
 | 
					                    class="avatar"
 | 
				
			||||||
 | 
					                    src={format!("data:image/jpeg;base64, {}", avatar)}
 | 
				
			||||||
 | 
					                    style={format!("max-height:{}px;max-width:{}px;height:auto;width:auto;", props.height, props.width)}
 | 
				
			||||||
 | 
					                    alt="Avatar" />
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        None => html! {
 | 
				
			||||||
 | 
					            <svg xmlns="http://www.w3.org/2000/svg"
 | 
				
			||||||
 | 
					                    width={props.width.to_string()}
 | 
				
			||||||
 | 
					                    height={props.height.to_string()}
 | 
				
			||||||
 | 
					                    fill="currentColor"
 | 
				
			||||||
 | 
					                    class="bi bi-person-circle"
 | 
				
			||||||
 | 
					                    viewBox="0 0 16 16">
 | 
				
			||||||
 | 
					                    <path d="M11 6a3 3 0 1 1-6 0 3 3 0 0 1 6 0z"/>
 | 
				
			||||||
 | 
					                    <path fill-rule="evenodd" d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8zm8-7a7 7 0 0 0-5.468 11.37C3.242 11.226 4.805 10 8 10s4.757 1.225 5.468 2.37A7 7 0 0 0 8 1z"/>
 | 
				
			||||||
 | 
					                </svg>
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										148
									
								
								app/src/components/avatar_cache.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										148
									
								
								app/src/components/avatar_cache.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,148 @@
 | 
				
			|||||||
 | 
					use crate::infra::api::HostService;
 | 
				
			||||||
 | 
					use anyhow::Result;
 | 
				
			||||||
 | 
					use gloo_console::error;
 | 
				
			||||||
 | 
					use graphql_client::GraphQLQuery;
 | 
				
			||||||
 | 
					use std::{collections::HashMap, rc::Rc};
 | 
				
			||||||
 | 
					use yew::prelude::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(GraphQLQuery)]
 | 
				
			||||||
 | 
					#[graphql(
 | 
				
			||||||
 | 
					    schema_path = "../schema.graphql",
 | 
				
			||||||
 | 
					    query_path = "queries/get_user_avatar.graphql",
 | 
				
			||||||
 | 
					    response_derives = "Debug",
 | 
				
			||||||
 | 
					    custom_scalars_module = "crate::infra::graphql"
 | 
				
			||||||
 | 
					)]
 | 
				
			||||||
 | 
					pub struct GetUserAvatar;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(GraphQLQuery)]
 | 
				
			||||||
 | 
					#[graphql(
 | 
				
			||||||
 | 
					    schema_path = "../schema.graphql",
 | 
				
			||||||
 | 
					    query_path = "queries/list_users.graphql",
 | 
				
			||||||
 | 
					    response_derives = "Debug",
 | 
				
			||||||
 | 
					    variables_derives = "Clone",
 | 
				
			||||||
 | 
					    custom_scalars_module = "crate::infra::graphql"
 | 
				
			||||||
 | 
					)]
 | 
				
			||||||
 | 
					pub struct ListUserNames;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(PartialEq, Clone)]
 | 
				
			||||||
 | 
					pub enum CacheAction {
 | 
				
			||||||
 | 
					    Clear,
 | 
				
			||||||
 | 
					    AddAvatar((String, Option<String>)),
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(PartialEq, Eq, Clone)]
 | 
				
			||||||
 | 
					pub struct AvatarCache {
 | 
				
			||||||
 | 
					    pub avatars: HashMap<String, Option<String>>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Reducible for AvatarCache {
 | 
				
			||||||
 | 
					    type Action = CacheAction;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn reduce(self: Rc<Self>, action: Self::Action) -> Rc<Self> {
 | 
				
			||||||
 | 
					        match action {
 | 
				
			||||||
 | 
					            CacheAction::AddAvatar((username, avatar)) => {
 | 
				
			||||||
 | 
					                let mut avatars = self.avatars.clone();
 | 
				
			||||||
 | 
					                avatars.insert(username, avatar);
 | 
				
			||||||
 | 
					                AvatarCache { avatars }.into()
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            CacheAction::Clear => AvatarCache {
 | 
				
			||||||
 | 
					                avatars: HashMap::new(),
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            .into(),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub type AvatarCacheContext = UseReducerHandle<AvatarCache>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(PartialEq, Clone)]
 | 
				
			||||||
 | 
					pub enum CacheMode {
 | 
				
			||||||
 | 
					    AllUsers,
 | 
				
			||||||
 | 
					    SingleUser(String),
 | 
				
			||||||
 | 
					    None,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Properties, PartialEq)]
 | 
				
			||||||
 | 
					pub struct AvatarCacheProviderProps {
 | 
				
			||||||
 | 
					    #[prop_or_default]
 | 
				
			||||||
 | 
					    pub children: Children,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub mode: CacheMode,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[function_component(AvatarCacheProvider)]
 | 
				
			||||||
 | 
					pub fn avatar_cache_provider(props: &AvatarCacheProviderProps) -> Html {
 | 
				
			||||||
 | 
					    let cache = use_reducer(|| AvatarCache {
 | 
				
			||||||
 | 
					        avatars: HashMap::new(),
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        let cache = cache.clone();
 | 
				
			||||||
 | 
					        let mode = props.mode.clone();
 | 
				
			||||||
 | 
					        use_effect_with_deps(
 | 
				
			||||||
 | 
					            move |mode| {
 | 
				
			||||||
 | 
					                match mode {
 | 
				
			||||||
 | 
					                    CacheMode::None => cache.dispatch(CacheAction::Clear),
 | 
				
			||||||
 | 
					                    CacheMode::AllUsers => {
 | 
				
			||||||
 | 
					                        let cache = cache.clone();
 | 
				
			||||||
 | 
					                        wasm_bindgen_futures::spawn_local(async move {
 | 
				
			||||||
 | 
					                            let result = fetch_all_avatars(cache).await;
 | 
				
			||||||
 | 
					                            if let Err(e) = result {
 | 
				
			||||||
 | 
					                                error!(&format!("Could not fetch all avatars: {e:#}"))
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        });
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    CacheMode::SingleUser(username) => {
 | 
				
			||||||
 | 
					                        let cache = cache.clone();
 | 
				
			||||||
 | 
					                        let username = username.clone();
 | 
				
			||||||
 | 
					                        wasm_bindgen_futures::spawn_local(async move {
 | 
				
			||||||
 | 
					                            let result = HostService::graphql_query::<GetUserAvatar>(
 | 
				
			||||||
 | 
					                                get_user_avatar::Variables { id: username },
 | 
				
			||||||
 | 
					                                "Error trying to fetch user avatar",
 | 
				
			||||||
 | 
					                            )
 | 
				
			||||||
 | 
					                            .await;
 | 
				
			||||||
 | 
					                            if let Ok(response) = result {
 | 
				
			||||||
 | 
					                                cache.dispatch(CacheAction::AddAvatar((
 | 
				
			||||||
 | 
					                                    response.user.id,
 | 
				
			||||||
 | 
					                                    response.user.avatar,
 | 
				
			||||||
 | 
					                                )))
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        });
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					                move || cache.dispatch(CacheAction::Clear)
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            mode,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    html! {
 | 
				
			||||||
 | 
					        <ContextProvider<AvatarCacheContext> context={cache}>
 | 
				
			||||||
 | 
					            {props.children.clone()}
 | 
				
			||||||
 | 
					        </ContextProvider<AvatarCacheContext>>
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async fn fetch_all_avatars(cache: UseReducerHandle<AvatarCache>) -> Result<()> {
 | 
				
			||||||
 | 
					    let response = HostService::graphql_query::<ListUserNames>(
 | 
				
			||||||
 | 
					        list_user_names::Variables { filters: None },
 | 
				
			||||||
 | 
					        "Error trying to fetch user list",
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    .await?;
 | 
				
			||||||
 | 
					    for user in &response.users {
 | 
				
			||||||
 | 
					        let result = HostService::graphql_query::<GetUserAvatar>(
 | 
				
			||||||
 | 
					            get_user_avatar::Variables {
 | 
				
			||||||
 | 
					                id: user.id.clone(),
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            "Error trying to fetch user avatar",
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        .await;
 | 
				
			||||||
 | 
					        if let Ok(response) = result {
 | 
				
			||||||
 | 
					            cache.dispatch(CacheAction::AddAvatar((
 | 
				
			||||||
 | 
					                response.user.id,
 | 
				
			||||||
 | 
					                response.user.avatar,
 | 
				
			||||||
 | 
					            )));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return Ok(());
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -1,6 +1,8 @@
 | 
				
			|||||||
pub mod add_group_member;
 | 
					pub mod add_group_member;
 | 
				
			||||||
pub mod add_user_to_group;
 | 
					pub mod add_user_to_group;
 | 
				
			||||||
pub mod app;
 | 
					pub mod app;
 | 
				
			||||||
 | 
					pub mod avatar;
 | 
				
			||||||
 | 
					pub mod avatar_cache;
 | 
				
			||||||
pub mod change_password;
 | 
					pub mod change_password;
 | 
				
			||||||
pub mod create_group;
 | 
					pub mod create_group;
 | 
				
			||||||
pub mod create_user;
 | 
					pub mod create_user;
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,7 @@
 | 
				
			|||||||
use std::str::FromStr;
 | 
					use std::str::FromStr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::{
 | 
					use crate::{
 | 
				
			||||||
 | 
					    components::avatar_cache::*,
 | 
				
			||||||
    components::user_details::User,
 | 
					    components::user_details::User,
 | 
				
			||||||
    infra::common_component::{CommonComponent, CommonComponentParts},
 | 
					    infra::common_component::{CommonComponent, CommonComponentParts},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
@ -12,6 +13,7 @@ use gloo_file::{
 | 
				
			|||||||
use graphql_client::GraphQLQuery;
 | 
					use graphql_client::GraphQLQuery;
 | 
				
			||||||
use validator_derive::Validate;
 | 
					use validator_derive::Validate;
 | 
				
			||||||
use web_sys::{FileList, HtmlInputElement, InputEvent};
 | 
					use web_sys::{FileList, HtmlInputElement, InputEvent};
 | 
				
			||||||
 | 
					use yew::context::ContextHandle;
 | 
				
			||||||
use yew::prelude::*;
 | 
					use yew::prelude::*;
 | 
				
			||||||
use yew_form_derive::Model;
 | 
					use yew_form_derive::Model;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -72,6 +74,8 @@ pub struct UserDetailsForm {
 | 
				
			|||||||
    /// True if we just successfully updated the user, to display a success message.
 | 
					    /// True if we just successfully updated the user, to display a success message.
 | 
				
			||||||
    just_updated: bool,
 | 
					    just_updated: bool,
 | 
				
			||||||
    user: User,
 | 
					    user: User,
 | 
				
			||||||
 | 
					    avatar_cache: AvatarCacheContext,
 | 
				
			||||||
 | 
					    _context_handle: ContextHandle<AvatarCacheContext>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub enum Msg {
 | 
					pub enum Msg {
 | 
				
			||||||
@ -156,6 +160,10 @@ impl Component for UserDetailsForm {
 | 
				
			|||||||
            first_name: ctx.props().user.first_name.clone(),
 | 
					            first_name: ctx.props().user.first_name.clone(),
 | 
				
			||||||
            last_name: ctx.props().user.last_name.clone(),
 | 
					            last_name: ctx.props().user.last_name.clone(),
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					        let (avatar_cache, _context_handle) = ctx
 | 
				
			||||||
 | 
					            .link()
 | 
				
			||||||
 | 
					            .context(Callback::noop())
 | 
				
			||||||
 | 
					            .expect("No Message Context Provided");
 | 
				
			||||||
        Self {
 | 
					        Self {
 | 
				
			||||||
            common: CommonComponentParts::<Self>::create(),
 | 
					            common: CommonComponentParts::<Self>::create(),
 | 
				
			||||||
            form: yew_form::Form::new(model),
 | 
					            form: yew_form::Form::new(model),
 | 
				
			||||||
@ -163,6 +171,8 @@ impl Component for UserDetailsForm {
 | 
				
			|||||||
            just_updated: false,
 | 
					            just_updated: false,
 | 
				
			||||||
            reader: None,
 | 
					            reader: None,
 | 
				
			||||||
            user: ctx.props().user.clone(),
 | 
					            user: ctx.props().user.clone(),
 | 
				
			||||||
 | 
					            avatar_cache,
 | 
				
			||||||
 | 
					            _context_handle,
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -402,6 +412,10 @@ impl UserDetailsForm {
 | 
				
			|||||||
            self.user.avatar = Some(avatar);
 | 
					            self.user.avatar = Some(avatar);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        self.just_updated = true;
 | 
					        self.just_updated = true;
 | 
				
			||||||
 | 
					        self.avatar_cache.dispatch(CacheAction::AddAvatar((
 | 
				
			||||||
 | 
					            self.user.id.clone(),
 | 
				
			||||||
 | 
					            self.user.avatar.clone(),
 | 
				
			||||||
 | 
					        )));
 | 
				
			||||||
        Ok(true)
 | 
					        Ok(true)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -30,3 +30,7 @@ html.dark .nav-link {
 | 
				
			|||||||
.nav-link {
 | 
					.nav-link {
 | 
				
			||||||
  color: #212529
 | 
					  color: #212529
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.avatar {
 | 
				
			||||||
 | 
					  border-radius: 50%;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user