diff --git a/Cargo.lock b/Cargo.lock
index 49e6872..40934b5 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1532,6 +1532,25 @@ dependencies = [
"gloo-utils",
]
+[[package]]
+name = "gloo"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3a4bef6b277b3ab073253d4bca60761240cf8d6998f4bd142211957b69a61b20"
+dependencies = [
+ "gloo-console",
+ "gloo-dialogs",
+ "gloo-events",
+ "gloo-file",
+ "gloo-history",
+ "gloo-net",
+ "gloo-render",
+ "gloo-storage",
+ "gloo-timers",
+ "gloo-utils",
+ "gloo-worker 0.2.1",
+]
+
[[package]]
name = "gloo-console"
version = "0.2.3"
@@ -1578,6 +1597,22 @@ dependencies = [
"web-sys",
]
+[[package]]
+name = "gloo-history"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dd451019e0b7a2b8a7a7b23e74916601abf1135c54664e57ff71dcc26dfcdeb7"
+dependencies = [
+ "gloo-events",
+ "gloo-utils",
+ "serde",
+ "serde-wasm-bindgen 0.4.5",
+ "serde_urlencoded",
+ "thiserror",
+ "wasm-bindgen",
+ "web-sys",
+]
+
[[package]]
name = "gloo-net"
version = "0.2.6"
@@ -1648,6 +1683,40 @@ dependencies = [
"web-sys",
]
+[[package]]
+name = "gloo-worker"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09110b5555bcafe508cee0fb94308af9aac7a85f980d3c88b270d117c6c6911d"
+dependencies = [
+ "anymap2",
+ "bincode",
+ "gloo-console",
+ "gloo-utils",
+ "js-sys",
+ "serde",
+ "slab",
+ "wasm-bindgen",
+ "web-sys",
+]
+
+[[package]]
+name = "gloo-worker"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "13471584da78061a28306d1359dd0178d8d6fc1c7c80e5e35d27260346e0516a"
+dependencies = [
+ "anymap2",
+ "bincode",
+ "gloo-console",
+ "gloo-utils",
+ "js-sys",
+ "serde",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+ "web-sys",
+]
+
[[package]]
name = "graphql-introspection-query"
version = "0.2.0"
@@ -2044,6 +2113,15 @@ dependencies = [
"num-traits",
]
+[[package]]
+name = "implicit-clone"
+version = "0.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "40fc102e70475c320b185cd18c1e48bba2d7210b63970a4d581ef903e4368ef7"
+dependencies = [
+ "indexmap",
+]
+
[[package]]
name = "indexmap"
version = "1.6.2"
@@ -2410,7 +2488,7 @@ dependencies = [
"tracing-forest",
"tracing-log",
"tracing-subscriber",
- "uuid 0.8.2",
+ "uuid 1.3.0",
"webpki-roots",
]
@@ -2439,7 +2517,7 @@ dependencies = [
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
- "yew",
+ "yew 0.19.3",
"yew-agent",
"yew-router",
"yew_form",
@@ -2537,12 +2615,6 @@ dependencies = [
"digest 0.10.6",
]
-[[package]]
-name = "md5"
-version = "0.7.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771"
-
[[package]]
name = "memchr"
version = "2.5.0"
@@ -3003,6 +3075,17 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
+[[package]]
+name = "pinned"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a829027bd95e54cfe13e3e258a1ae7b645960553fb82b75ff852c29688ee595b"
+dependencies = [
+ "futures",
+ "rustversion",
+ "thiserror",
+]
+
[[package]]
name = "pkcs1"
version = "0.3.3"
@@ -3067,6 +3150,16 @@ dependencies = [
"termtree",
]
+[[package]]
+name = "prettyplease"
+version = "0.1.25"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6c8646e95016a7a6c4adea95bafa8a16baab64b583356217f2c85db4a39d9a86"
+dependencies = [
+ "proc-macro2",
+ "syn",
+]
+
[[package]]
name = "proc-macro-error"
version = "1.0.4"
@@ -3113,6 +3206,23 @@ dependencies = [
"yansi",
]
+[[package]]
+name = "prokio"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "03b55e106e5791fa5a13abd13c85d6127312e8e09098059ca2bc9b03ca4cf488"
+dependencies = [
+ "futures",
+ "gloo 0.8.0",
+ "num_cpus",
+ "once_cell",
+ "pin-project",
+ "pinned",
+ "tokio",
+ "tokio-stream",
+ "wasm-bindgen-futures",
+]
+
[[package]]
name = "quote"
version = "1.0.23"
@@ -3645,6 +3755,17 @@ dependencies = [
"wasm-bindgen",
]
+[[package]]
+name = "serde-wasm-bindgen"
+version = "0.4.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3b4c031cd0d9014307d82b8abf653c0290fbdaeb4c02d00c63cf52f728628bf"
+dependencies = [
+ "js-sys",
+ "serde",
+ "wasm-bindgen",
+]
+
[[package]]
name = "serde_bytes"
version = "0.11.9"
@@ -4411,9 +4532,6 @@ name = "uuid"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"
-dependencies = [
- "md5",
-]
[[package]]
name = "uuid"
@@ -4422,6 +4540,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1674845326ee10d37ca60470760d4288a6f80f304007d92e5c53bab78c9cfd79"
dependencies = [
"getrandom 0.2.8",
+ "md-5",
]
[[package]]
@@ -4775,7 +4894,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a1ccb53e57d3f7d847338cf5758befa811cabe207df07f543c06f502f9998cd"
dependencies = [
"console_error_panic_hook",
- "gloo",
+ "gloo 0.4.2",
"gloo-utils",
"indexmap",
"js-sys",
@@ -4784,26 +4903,42 @@ dependencies = [
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
- "yew-macro",
+ "yew-macro 0.19.3",
+]
+
+[[package]]
+name = "yew"
+version = "0.20.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5dbecfe44343b70cc2932c3eb445425969ae21754a8ab3a0966981c1cf7af1cc"
+dependencies = [
+ "console_error_panic_hook",
+ "futures",
+ "gloo 0.8.0",
+ "implicit-clone",
+ "indexmap",
+ "js-sys",
+ "prokio",
+ "rustversion",
+ "serde",
+ "slab",
+ "thiserror",
+ "tokio",
+ "tracing",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+ "web-sys",
+ "yew-macro 0.20.0",
]
[[package]]
name = "yew-agent"
-version = "0.1.0"
+version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "616700dc3851945658c44ba4477ede6b77c795462fbbb9b0ad9a8b6273a3ca77"
+checksum = "b06f7c5ed97fff22816bb00d3d82ebc0fc1119d7bbb9e07e62c0d2853f51920a"
dependencies = [
- "anymap2",
- "bincode",
- "gloo-console",
- "gloo-utils",
- "js-sys",
- "serde",
- "slab",
- "wasm-bindgen",
- "wasm-bindgen-futures",
- "web-sys",
- "yew",
+ "gloo-worker 0.1.2",
+ "yew 0.20.0",
]
[[package]]
@@ -4820,23 +4955,38 @@ dependencies = [
"syn",
]
+[[package]]
+name = "yew-macro"
+version = "0.20.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b64c253c1d401f1ea868ca9988db63958cfa15a69f739101f338d6f05eea8301"
+dependencies = [
+ "boolinator",
+ "once_cell",
+ "prettyplease",
+ "proc-macro-error",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
[[package]]
name = "yew-router"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "155804f6f3aa309f596d5c3fa14486a94e7756f1edd7634569949e401d5099f2"
dependencies = [
- "gloo",
+ "gloo 0.4.2",
"gloo-utils",
"js-sys",
"route-recognizer",
"serde",
- "serde-wasm-bindgen",
+ "serde-wasm-bindgen 0.3.1",
"serde_urlencoded",
"thiserror",
"wasm-bindgen",
"web-sys",
- "yew",
+ "yew 0.19.3",
"yew-router-macro",
]
@@ -4861,7 +5011,7 @@ dependencies = [
"validator_derive",
"wasm-bindgen",
"web-sys",
- "yew",
+ "yew 0.19.3",
]
[[package]]
diff --git a/app/Cargo.toml b/app/Cargo.toml
index 7f570be..844924c 100644
--- a/app/Cargo.toml
+++ b/app/Cargo.toml
@@ -24,7 +24,7 @@ wasm-bindgen = "0.2"
wasm-bindgen-futures = "*"
yew = "0.19.3"
yew-router = "0.16"
-yew-agent = "0.1.0"
+yew-agent = "0.2.0"
# Needed because of https://github.com/tkaitchuck/aHash/issues/95
indexmap = "=1.6.2"
diff --git a/app/queries/get_user_avatar.graphql b/app/queries/get_user_avatar.graphql
index 587a9f9..28d2bd8 100644
--- a/app/queries/get_user_avatar.graphql
+++ b/app/queries/get_user_avatar.graphql
@@ -1,5 +1,6 @@
query GetUserAvatar($id: String!) {
user(userId: $id) {
+ id
avatar
}
}
diff --git a/app/src/components/app.rs b/app/src/components/app.rs
index 5d5ad0b..7f40690 100644
--- a/app/src/components/app.rs
+++ b/app/src/components/app.rs
@@ -1,6 +1,7 @@
use crate::{
components::{
avatar::ShowAvatar,
+ avatar_cache::*,
change_password::ChangePasswordForm,
create_group::CreateGroupForm,
create_user::CreateUserForm,
@@ -137,8 +138,19 @@ impl Component for App {
let link = ctx.link().clone();
let is_admin = self.is_admin();
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! {
-
+
{self.view_banner(ctx)}
@@ -150,7 +162,7 @@ impl Component for App {
{self.view_footer()}
-
+
}
}
}
diff --git a/app/src/components/avatar.rs b/app/src/components/avatar.rs
index d652bbe..f8ee8c5 100644
--- a/app/src/components/avatar.rs
+++ b/app/src/components/avatar.rs
@@ -1,133 +1,37 @@
use crate::{
- components::avatar_event_bus::{AvatarEventBus, Response},
- infra::common_component::{CommonComponent, CommonComponentParts},
+ components::avatar_cache::{AvatarCacheContext},
};
-use anyhow::{bail, Result};
-use graphql_client::GraphQLQuery;
-use serde::{Deserialize, Serialize};
-use yew::prelude::*;
-use yew_agent::{Bridge, Bridged};
+use yew::{function_component, 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(Serialize, Deserialize, Debug, Clone)]
-pub struct AvatarData(String);
-
-impl AvatarData {
- pub fn new(data: String) -> Self {
- AvatarData(data)
- }
-}
-
-pub struct ShowAvatar {
- common: CommonComponentParts,
- avatar: Option,
- _producer: Box>,
-}
-
-/// State machine describing the possible transitions of the component state.
-/// It starts out by fetching the user's details from the backend when loading.
-pub enum Msg {
- /// Received the user details response, either the user data or an error.
- UserAvatarResponse(Result),
- Update(Response),
-}
-
-#[derive(yew::Properties, Clone, PartialEq, Eq)]
+#[derive(Properties, PartialEq)]
pub struct Props {
pub username: String,
pub width: i32,
pub height: i32,
}
-impl CommonComponent for ShowAvatar {
- fn handle_msg(
- &mut self,
- ctx: &Context,
- msg: ::Message,
- ) -> Result {
- match msg {
- Msg::UserAvatarResponse(response) => match response {
- Ok(user) => self.avatar = user.user.avatar.map(AvatarData::new),
- Err(e) => {
- self.avatar = None;
- bail!("Error getting user avatar: {}", e);
- }
- },
- Msg::Update(Response::Update((username, avatar))) => {
- if username == ctx.props().username {
- self.avatar = avatar;
- return Ok(true);
- }
- return Ok(false);
- }
- }
- Ok(true)
- }
-
- fn mut_common(&mut self) -> &mut CommonComponentParts {
- &mut self.common
- }
-}
-
-impl ShowAvatar {
- fn get_user_avatar(&mut self, ctx: &Context) {
- self.common.call_graphql::(
- ctx,
- get_user_avatar::Variables {
- id: ctx.props().username.clone(),
- },
- Msg::UserAvatarResponse,
- "Error trying to fetch user avatar",
- )
- }
-}
-
-impl Component for ShowAvatar {
- type Message = Msg;
- type Properties = Props;
-
- fn create(ctx: &Context) -> Self {
- let mut avatar = Self {
- common: CommonComponentParts::::create(),
- avatar: None,
- _producer: AvatarEventBus::bridge(ctx.link().callback(Msg::Update)),
- };
- avatar.get_user_avatar(ctx);
- avatar
- }
-
- fn update(&mut self, ctx: &Context, msg: Self::Message) -> bool {
- CommonComponentParts::::update(self, ctx, msg)
- }
-
- fn view(&self, ctx: &Context) -> Html {
- match &self.avatar {
- Some(avatar) => html! {
-
- },
- None => html! {
-
- },
- }
+#[function_component(ShowAvatar)]
+pub fn show_avatar(props: &Props) -> Html {
+ let cache = use_context::().expect("no ctx found");
+ let avatar = cache.avatars.get(&props.username).map(|val| val.clone()).unwrap_or(None);
+ match avatar {
+ Some(avatar) => html! {
+
+ },
+ None => html! {
+
+ },
}
}
diff --git a/app/src/components/avatar_cache.rs b/app/src/components/avatar_cache.rs
new file mode 100644
index 0000000..a11e6ac
--- /dev/null
+++ b/app/src/components/avatar_cache.rs
@@ -0,0 +1,150 @@
+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,Clone,PartialEq,Eq,Hash",
+ variables_derives = "Clone",
+ custom_scalars_module = "crate::infra::graphql"
+)]
+pub struct ListUserNames;
+
+#[derive(Debug, PartialEq, Clone)]
+pub enum CacheAction {
+ Clear,
+ AddAvatar((String, Option)),
+}
+
+#[derive(Debug, PartialEq, Eq, Clone)]
+pub struct AvatarCache {
+ pub avatars: HashMap>,
+}
+
+impl Reducible for AvatarCache {
+ type Action = CacheAction;
+
+ fn reduce(self: Rc, action: Self::Action) -> Rc {
+ 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;
+
+#[derive(Debug, PartialEq, Clone)]
+pub enum CacheMode {
+ AllUsers,
+ SingleUser(String),
+ None,
+}
+
+#[derive(Properties, Debug, 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::(
+ 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! {
+ context={cache}>
+ {props.children.clone()}
+ >
+ }
+}
+
+async fn fetch_all_avatars(cache: UseReducerHandle) -> Result<()> {
+ let response = HostService::graphql_query::(
+ list_user_names::Variables { filters: None },
+ "Error trying to fetch user list",
+ )
+ .await?;
+ for user in &response.users {
+ let result = HostService::graphql_query::(
+ 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(());
+}
diff --git a/app/src/components/avatar_event_bus.rs b/app/src/components/avatar_event_bus.rs
deleted file mode 100644
index 5b62e66..0000000
--- a/app/src/components/avatar_event_bus.rs
+++ /dev/null
@@ -1,55 +0,0 @@
-use serde::{Deserialize, Serialize};
-use std::collections::HashSet;
-use yew_agent::{Agent, AgentLink, Context, HandlerId};
-
-use super::avatar::AvatarData;
-
-#[derive(Serialize, Deserialize, Debug)]
-pub enum Request {
- Update((String, Option)),
-}
-
-#[derive(Serialize, Deserialize, Debug)]
-pub enum Response {
- Update((String, Option)),
-}
-
-pub struct AvatarEventBus {
- link: AgentLink,
- subscribers: HashSet,
-}
-
-impl Agent for AvatarEventBus {
- type Reach = Context;
- type Message = ();
- type Input = Request;
- type Output = Response;
-
- fn create(link: AgentLink) -> Self {
- Self {
- link,
- subscribers: HashSet::new(),
- }
- }
-
- fn update(&mut self, _msg: Self::Message) {}
-
- fn handle_input(&mut self, msg: Self::Input, _id: HandlerId) {
- match msg {
- Request::Update((username, avatar)) => {
- for sub in self.subscribers.iter() {
- self.link
- .respond(*sub, Response::Update((username.clone(), avatar.clone())));
- }
- }
- }
- }
-
- fn connected(&mut self, id: HandlerId) {
- self.subscribers.insert(id);
- }
-
- fn disconnected(&mut self, id: HandlerId) {
- self.subscribers.remove(&id);
- }
-}
diff --git a/app/src/components/mod.rs b/app/src/components/mod.rs
index c406b64..6690e04 100644
--- a/app/src/components/mod.rs
+++ b/app/src/components/mod.rs
@@ -2,7 +2,7 @@ pub mod add_group_member;
pub mod add_user_to_group;
pub mod app;
pub mod avatar;
-pub mod avatar_event_bus;
+pub mod avatar_cache;
pub mod change_password;
pub mod create_group;
pub mod create_user;
diff --git a/app/src/components/user_details_form.rs b/app/src/components/user_details_form.rs
index 6872dc1..e657376 100644
--- a/app/src/components/user_details_form.rs
+++ b/app/src/components/user_details_form.rs
@@ -1,8 +1,7 @@
use std::str::FromStr;
use crate::{
- components::avatar::AvatarData,
- components::avatar_event_bus::{AvatarEventBus, Request},
+ components::avatar_cache::*,
components::user_details::User,
infra::common_component::{CommonComponent, CommonComponentParts},
};
@@ -15,7 +14,7 @@ use graphql_client::GraphQLQuery;
use validator_derive::Validate;
use web_sys::{FileList, HtmlInputElement, InputEvent};
use yew::prelude::*;
-use yew_agent::{Dispatched, Dispatcher};
+use yew::context::ContextHandle;
use yew_form_derive::Model;
#[derive(Default)]
@@ -75,7 +74,8 @@ pub struct UserDetailsForm {
/// True if we just successfully updated the user, to display a success message.
just_updated: bool,
user: User,
- avatar_event_bus: Dispatcher,
+ avatar_cache: AvatarCacheContext,
+ _context_handle: ContextHandle,
}
pub enum Msg {
@@ -160,6 +160,10 @@ impl Component for UserDetailsForm {
first_name: ctx.props().user.first_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 {
common: CommonComponentParts::::create(),
form: yew_form::Form::new(model),
@@ -167,7 +171,8 @@ impl Component for UserDetailsForm {
just_updated: false,
reader: None,
user: ctx.props().user.clone(),
- avatar_event_bus: AvatarEventBus::dispatcher(),
+ avatar_cache,
+ _context_handle,
}
}
@@ -407,13 +412,7 @@ impl UserDetailsForm {
self.user.avatar = Some(avatar);
}
self.just_updated = true;
- self.avatar_event_bus.send(Request::Update((
- self.user.id.clone(),
- self.user
- .avatar
- .as_ref()
- .map(|data| AvatarData::new(data.clone())),
- )));
+ self.avatar_cache.dispatch(CacheAction::AddAvatar((self.user.id.clone(), self.user.avatar.clone())));
Ok(true)
}