mirror of
https://github.com/nitnelave/lldap.git
synced 2023-04-12 14:25:13 +00:00
Refactor to context and reducer
This commit is contained in:
parent
cbc6c87d48
commit
e2fd9686a8
210
Cargo.lock
generated
210
Cargo.lock
generated
@ -1532,6 +1532,25 @@ dependencies = [
|
|||||||
"gloo-utils",
|
"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]]
|
[[package]]
|
||||||
name = "gloo-console"
|
name = "gloo-console"
|
||||||
version = "0.2.3"
|
version = "0.2.3"
|
||||||
@ -1578,6 +1597,22 @@ dependencies = [
|
|||||||
"web-sys",
|
"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]]
|
[[package]]
|
||||||
name = "gloo-net"
|
name = "gloo-net"
|
||||||
version = "0.2.6"
|
version = "0.2.6"
|
||||||
@ -1648,6 +1683,40 @@ dependencies = [
|
|||||||
"web-sys",
|
"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]]
|
[[package]]
|
||||||
name = "graphql-introspection-query"
|
name = "graphql-introspection-query"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
@ -2044,6 +2113,15 @@ dependencies = [
|
|||||||
"num-traits",
|
"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]]
|
[[package]]
|
||||||
name = "indexmap"
|
name = "indexmap"
|
||||||
version = "1.6.2"
|
version = "1.6.2"
|
||||||
@ -2410,7 +2488,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",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -2439,7 +2517,7 @@ dependencies = [
|
|||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
"wasm-bindgen-futures",
|
"wasm-bindgen-futures",
|
||||||
"web-sys",
|
"web-sys",
|
||||||
"yew",
|
"yew 0.19.3",
|
||||||
"yew-agent",
|
"yew-agent",
|
||||||
"yew-router",
|
"yew-router",
|
||||||
"yew_form",
|
"yew_form",
|
||||||
@ -2537,12 +2615,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"
|
||||||
@ -3003,6 +3075,17 @@ version = "0.1.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
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]]
|
[[package]]
|
||||||
name = "pkcs1"
|
name = "pkcs1"
|
||||||
version = "0.3.3"
|
version = "0.3.3"
|
||||||
@ -3067,6 +3150,16 @@ dependencies = [
|
|||||||
"termtree",
|
"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]]
|
[[package]]
|
||||||
name = "proc-macro-error"
|
name = "proc-macro-error"
|
||||||
version = "1.0.4"
|
version = "1.0.4"
|
||||||
@ -3113,6 +3206,23 @@ dependencies = [
|
|||||||
"yansi",
|
"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]]
|
[[package]]
|
||||||
name = "quote"
|
name = "quote"
|
||||||
version = "1.0.23"
|
version = "1.0.23"
|
||||||
@ -3645,6 +3755,17 @@ dependencies = [
|
|||||||
"wasm-bindgen",
|
"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]]
|
[[package]]
|
||||||
name = "serde_bytes"
|
name = "serde_bytes"
|
||||||
version = "0.11.9"
|
version = "0.11.9"
|
||||||
@ -4411,9 +4532,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"
|
||||||
@ -4422,6 +4540,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]]
|
||||||
@ -4775,7 +4894,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "2a1ccb53e57d3f7d847338cf5758befa811cabe207df07f543c06f502f9998cd"
|
checksum = "2a1ccb53e57d3f7d847338cf5758befa811cabe207df07f543c06f502f9998cd"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"console_error_panic_hook",
|
"console_error_panic_hook",
|
||||||
"gloo",
|
"gloo 0.4.2",
|
||||||
"gloo-utils",
|
"gloo-utils",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
@ -4784,26 +4903,42 @@ dependencies = [
|
|||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
"wasm-bindgen-futures",
|
"wasm-bindgen-futures",
|
||||||
"web-sys",
|
"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]]
|
[[package]]
|
||||||
name = "yew-agent"
|
name = "yew-agent"
|
||||||
version = "0.1.0"
|
version = "0.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "616700dc3851945658c44ba4477ede6b77c795462fbbb9b0ad9a8b6273a3ca77"
|
checksum = "b06f7c5ed97fff22816bb00d3d82ebc0fc1119d7bbb9e07e62c0d2853f51920a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anymap2",
|
"gloo-worker 0.1.2",
|
||||||
"bincode",
|
"yew 0.20.0",
|
||||||
"gloo-console",
|
|
||||||
"gloo-utils",
|
|
||||||
"js-sys",
|
|
||||||
"serde",
|
|
||||||
"slab",
|
|
||||||
"wasm-bindgen",
|
|
||||||
"wasm-bindgen-futures",
|
|
||||||
"web-sys",
|
|
||||||
"yew",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -4820,23 +4955,38 @@ dependencies = [
|
|||||||
"syn",
|
"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]]
|
[[package]]
|
||||||
name = "yew-router"
|
name = "yew-router"
|
||||||
version = "0.16.0"
|
version = "0.16.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "155804f6f3aa309f596d5c3fa14486a94e7756f1edd7634569949e401d5099f2"
|
checksum = "155804f6f3aa309f596d5c3fa14486a94e7756f1edd7634569949e401d5099f2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"gloo",
|
"gloo 0.4.2",
|
||||||
"gloo-utils",
|
"gloo-utils",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"route-recognizer",
|
"route-recognizer",
|
||||||
"serde",
|
"serde",
|
||||||
"serde-wasm-bindgen",
|
"serde-wasm-bindgen 0.3.1",
|
||||||
"serde_urlencoded",
|
"serde_urlencoded",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
"web-sys",
|
"web-sys",
|
||||||
"yew",
|
"yew 0.19.3",
|
||||||
"yew-router-macro",
|
"yew-router-macro",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -4861,7 +5011,7 @@ dependencies = [
|
|||||||
"validator_derive",
|
"validator_derive",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
"web-sys",
|
"web-sys",
|
||||||
"yew",
|
"yew 0.19.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -24,7 +24,7 @@ wasm-bindgen = "0.2"
|
|||||||
wasm-bindgen-futures = "*"
|
wasm-bindgen-futures = "*"
|
||||||
yew = "0.19.3"
|
yew = "0.19.3"
|
||||||
yew-router = "0.16"
|
yew-router = "0.16"
|
||||||
yew-agent = "0.1.0"
|
yew-agent = "0.2.0"
|
||||||
|
|
||||||
# Needed because of https://github.com/tkaitchuck/aHash/issues/95
|
# Needed because of https://github.com/tkaitchuck/aHash/issues/95
|
||||||
indexmap = "=1.6.2"
|
indexmap = "=1.6.2"
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
query GetUserAvatar($id: String!) {
|
query GetUserAvatar($id: String!) {
|
||||||
user(userId: $id) {
|
user(userId: $id) {
|
||||||
|
id
|
||||||
avatar
|
avatar
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
components::{
|
components::{
|
||||||
avatar::ShowAvatar,
|
avatar::ShowAvatar,
|
||||||
|
avatar_cache::*,
|
||||||
change_password::ChangePasswordForm,
|
change_password::ChangePasswordForm,
|
||||||
create_group::CreateGroupForm,
|
create_group::CreateGroupForm,
|
||||||
create_user::CreateUserForm,
|
create_user::CreateUserForm,
|
||||||
@ -137,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;">
|
||||||
@ -150,7 +162,7 @@ impl Component for App {
|
|||||||
</div>
|
</div>
|
||||||
{self.view_footer()}
|
{self.view_footer()}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</AvatarCacheProvider>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,126 +1,31 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
components::avatar_event_bus::{AvatarEventBus, Response},
|
components::avatar_cache::{AvatarCacheContext},
|
||||||
infra::common_component::{CommonComponent, CommonComponentParts},
|
|
||||||
};
|
};
|
||||||
use anyhow::{bail, Result};
|
use yew::{function_component, prelude::*};
|
||||||
use graphql_client::GraphQLQuery;
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use yew::prelude::*;
|
|
||||||
use yew_agent::{Bridge, Bridged};
|
|
||||||
|
|
||||||
#[derive(GraphQLQuery)]
|
#[derive(Properties, PartialEq)]
|
||||||
#[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<Self>,
|
|
||||||
avatar: Option<AvatarData>,
|
|
||||||
_producer: Box<dyn Bridge<AvatarEventBus>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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<get_user_avatar::ResponseData>),
|
|
||||||
Update(Response),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(yew::Properties, Clone, PartialEq, Eq)]
|
|
||||||
pub struct Props {
|
pub struct Props {
|
||||||
pub username: String,
|
pub username: String,
|
||||||
pub width: i32,
|
pub width: i32,
|
||||||
pub height: i32,
|
pub height: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CommonComponent<ShowAvatar> for ShowAvatar {
|
#[function_component(ShowAvatar)]
|
||||||
fn handle_msg(
|
pub fn show_avatar(props: &Props) -> Html {
|
||||||
&mut self,
|
let cache = use_context::<AvatarCacheContext>().expect("no ctx found");
|
||||||
ctx: &Context<Self>,
|
let avatar = cache.avatars.get(&props.username).map(|val| val.clone()).unwrap_or(None);
|
||||||
msg: <Self as Component>::Message,
|
match avatar {
|
||||||
) -> Result<bool> {
|
|
||||||
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<Self> {
|
|
||||||
&mut self.common
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ShowAvatar {
|
|
||||||
fn get_user_avatar(&mut self, ctx: &Context<Self>) {
|
|
||||||
self.common.call_graphql::<GetUserAvatar, _>(
|
|
||||||
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>) -> Self {
|
|
||||||
let mut avatar = Self {
|
|
||||||
common: CommonComponentParts::<Self>::create(),
|
|
||||||
avatar: None,
|
|
||||||
_producer: AvatarEventBus::bridge(ctx.link().callback(Msg::Update)),
|
|
||||||
};
|
|
||||||
avatar.get_user_avatar(ctx);
|
|
||||||
avatar
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
|
|
||||||
CommonComponentParts::<Self>::update(self, ctx, msg)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view(&self, ctx: &Context<Self>) -> Html {
|
|
||||||
match &self.avatar {
|
|
||||||
Some(avatar) => html! {
|
Some(avatar) => html! {
|
||||||
<img
|
<img
|
||||||
class="avatar"
|
class="avatar"
|
||||||
src={format!("data:image/jpeg;base64, {}", avatar.0)}
|
src={format!("data:image/jpeg;base64, {}", avatar)}
|
||||||
style={format!("max-height:{}px;max-width:{}px;height:auto;width:auto;", ctx.props().height,ctx.props().width)}
|
style={format!("max-height:{}px;max-width:{}px;height:auto;width:auto;", props.height, props.width)}
|
||||||
alt="Avatar" />
|
alt="Avatar" />
|
||||||
},
|
},
|
||||||
None => html! {
|
None => html! {
|
||||||
<svg xmlns="http://www.w3.org/2000/svg"
|
<svg xmlns="http://www.w3.org/2000/svg"
|
||||||
width={ctx.props().width.to_string()}
|
width={props.width.to_string()}
|
||||||
height={ctx.props().height.to_string()}
|
height={props.height.to_string()}
|
||||||
fill="currentColor"
|
fill="currentColor"
|
||||||
class="bi bi-person-circle"
|
class="bi bi-person-circle"
|
||||||
viewBox="0 0 16 16">
|
viewBox="0 0 16 16">
|
||||||
@ -130,4 +35,3 @@ impl Component for ShowAvatar {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
150
app/src/components/avatar_cache.rs
Normal file
150
app/src/components/avatar_cache.rs
Normal file
@ -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<String>)),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, 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(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::<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,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<AvatarData>)),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
|
||||||
pub enum Response {
|
|
||||||
Update((String, Option<AvatarData>)),
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct AvatarEventBus {
|
|
||||||
link: AgentLink<AvatarEventBus>,
|
|
||||||
subscribers: HashSet<HandlerId>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Agent for AvatarEventBus {
|
|
||||||
type Reach = Context<Self>;
|
|
||||||
type Message = ();
|
|
||||||
type Input = Request;
|
|
||||||
type Output = Response;
|
|
||||||
|
|
||||||
fn create(link: AgentLink<Self>) -> 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);
|
|
||||||
}
|
|
||||||
}
|
|
@ -2,7 +2,7 @@ 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;
|
||||||
pub mod avatar_event_bus;
|
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,8 +1,7 @@
|
|||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
components::avatar::AvatarData,
|
components::avatar_cache::*,
|
||||||
components::avatar_event_bus::{AvatarEventBus, Request},
|
|
||||||
components::user_details::User,
|
components::user_details::User,
|
||||||
infra::common_component::{CommonComponent, CommonComponentParts},
|
infra::common_component::{CommonComponent, CommonComponentParts},
|
||||||
};
|
};
|
||||||
@ -15,7 +14,7 @@ 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::prelude::*;
|
use yew::prelude::*;
|
||||||
use yew_agent::{Dispatched, Dispatcher};
|
use yew::context::ContextHandle;
|
||||||
use yew_form_derive::Model;
|
use yew_form_derive::Model;
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
@ -75,7 +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_event_bus: Dispatcher<AvatarEventBus>,
|
avatar_cache: AvatarCacheContext,
|
||||||
|
_context_handle: ContextHandle<AvatarCacheContext>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum Msg {
|
pub enum Msg {
|
||||||
@ -160,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),
|
||||||
@ -167,7 +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_event_bus: AvatarEventBus::dispatcher(),
|
avatar_cache,
|
||||||
|
_context_handle,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -407,13 +412,7 @@ impl UserDetailsForm {
|
|||||||
self.user.avatar = Some(avatar);
|
self.user.avatar = Some(avatar);
|
||||||
}
|
}
|
||||||
self.just_updated = true;
|
self.just_updated = true;
|
||||||
self.avatar_event_bus.send(Request::Update((
|
self.avatar_cache.dispatch(CacheAction::AddAvatar((self.user.id.clone(), self.user.avatar.clone())));
|
||||||
self.user.id.clone(),
|
|
||||||
self.user
|
|
||||||
.avatar
|
|
||||||
.as_ref()
|
|
||||||
.map(|data| AvatarData::new(data.clone())),
|
|
||||||
)));
|
|
||||||
Ok(true)
|
Ok(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user