Web API, Web UI #86

Merged
projectmoon merged 37 commits from web-api into master 2021-07-15 15:04:54 +00:00
5 changed files with 140 additions and 150 deletions
Showing only changes of commit 9e0fd44448 - Show all commits

127
Cargo.lock generated
View File

@ -390,6 +390,12 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "cfg-match"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8100e46ff92eb85bf6dc2930c73f2a4f7176393c84a9446b3d501e1b354e7b34"
[[package]] [[package]]
name = "chacha20" name = "chacha20"
version = "0.6.0" version = "0.6.0"
@ -2728,12 +2734,6 @@ dependencies = [
"uncased", "uncased",
] ]
[[package]]
name = "route-recognizer"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "824172f0afccf3773c3905f5550ac94572144efe0deaf49a1f22bbca188d193e"
[[package]] [[package]]
name = "ruma" name = "ruma"
version = "0.1.2" version = "0.1.2"
@ -3014,12 +3014,6 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2" checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2"
[[package]]
name = "scoped-tls-hkt"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2e9d7eaddb227e8fbaaa71136ae0e1e913ca159b86c7da82f3e8f0044ad3a63"
[[package]] [[package]]
name = "scopeguard" name = "scopeguard"
version = "1.1.0" version = "1.1.0"
@ -3592,9 +3586,7 @@ dependencies = [
"wasm-bindgen-futures", "wasm-bindgen-futures",
"web-sys", "web-sys",
"yew", "yew",
"yew-functional",
"yew-router", "yew-router",
"yew-services",
"yewdux", "yewdux",
"yewtil", "yewtil",
] ]
@ -4221,28 +4213,6 @@ dependencies = [
"wasm-bindgen", "wasm-bindgen",
] ]
[[package]]
name = "weblog"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6eec0958e0181982bc8b4577b1363f21300a670603615c58643f172c92c47357"
dependencies = [
"wasm-bindgen",
"web-sys",
"weblog-proc-macro",
]
[[package]]
name = "weblog-proc-macro"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d9abb8ee84ede5408a346721d72fb216a27f53a539ff3c83ed1bf7625af7104"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "which" name = "which"
version = "4.1.0" version = "4.1.0"
@ -4335,18 +4305,22 @@ checksum = "9fc79f4a1e39857fc00c3f662cbf2651c771f00e9c15fe2abc341806bd46bd71"
[[package]] [[package]]
name = "yew" name = "yew"
version = "0.17.4" version = "0.18.0"
source = "git+https://github.com/yewstack/yew?rev=246bc59#246bc5960b504258b0603bc76760777e6650c91d" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e4d5154faef86dddd2eb333d4755ea5643787d20aca683e58759b0e53351409f"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"anymap", "anymap",
"bincode", "bincode",
"cfg-if 1.0.0",
"cfg-match",
"console_error_panic_hook", "console_error_panic_hook",
"gloo", "gloo",
"http", "http",
"indexmap", "indexmap",
"js-sys", "js-sys",
"log", "log",
"ryu",
"serde", "serde",
"serde_json", "serde_json",
"slab", "slab",
@ -4357,31 +4331,11 @@ dependencies = [
"yew-macro", "yew-macro",
] ]
[[package]]
name = "yew-functional"
version = "0.13.0"
source = "git+https://github.com/yewstack/yew?rev=246bc59#246bc5960b504258b0603bc76760777e6650c91d"
dependencies = [
"scoped-tls-hkt",
"wasm-bindgen",
"yew",
"yew-functional-macro",
]
[[package]]
name = "yew-functional-macro"
version = "0.1.0"
source = "git+https://github.com/yewstack/yew?rev=246bc59#246bc5960b504258b0603bc76760777e6650c91d"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "yew-macro" name = "yew-macro"
version = "0.17.0" version = "0.18.0"
source = "git+https://github.com/yewstack/yew?rev=246bc59#246bc5960b504258b0603bc76760777e6650c91d" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6e23bfe3dc3933fbe9592d149c9985f3047d08c637a884b9344c21e56e092ef"
dependencies = [ dependencies = [
"boolinator", "boolinator",
"lazy_static", "lazy_static",
@ -4392,68 +4346,65 @@ dependencies = [
[[package]] [[package]]
name = "yew-router" name = "yew-router"
version = "0.14.0" version = "0.15.0"
source = "git+https://github.com/yewstack/yew?rev=246bc59#246bc5960b504258b0603bc76760777e6650c91d" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "27666236d9597eac9be560e841e415e20ba67020bc8cd081076be178e159c8bc"
dependencies = [ dependencies = [
"cfg-if 1.0.0",
"cfg-match",
"gloo", "gloo",
"js-sys", "js-sys",
"route-recognizer", "log",
"nom 5.1.2",
"serde", "serde",
"serde_urlencoded", "serde_json",
"wasm-bindgen", "wasm-bindgen",
"web-sys", "web-sys",
"weblog",
"yew", "yew",
"yew-router-macro", "yew-router-macro",
"yew-router-route-parser",
] ]
[[package]] [[package]]
name = "yew-router-macro" name = "yew-router-macro"
version = "0.14.0" version = "0.15.0"
source = "git+https://github.com/yewstack/yew?rev=246bc59#246bc5960b504258b0603bc76760777e6650c91d" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c0ace2924b7a175e2d1c0e62ee7022a5ad840040dcd52414ce5f410ab322dba"
dependencies = [ dependencies = [
"heck",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn",
"yew-router-route-parser",
] ]
[[package]] [[package]]
name = "yew-services" name = "yew-router-route-parser"
version = "0.1.0" version = "0.15.0"
source = "git+https://github.com/yewstack/yew?rev=246bc59#246bc5960b504258b0603bc76760777e6650c91d" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de4a67208fb46b900af18a7397938b01f379dfc18da34799cfa8347eec715697"
dependencies = [ dependencies = [
"anyhow", "nom 5.1.2",
"gloo",
"http",
"js-sys",
"serde",
"serde_json",
"thiserror",
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
"yew",
] ]
[[package]] [[package]]
name = "yewdux" name = "yewdux"
version = "0.6.1" version = "0.6.2"
source = "git+https://github.com/deftsp/yewdux?rev=dbda686#dbda686dea05c0efaef0cd3af46012033071f40e" source = "git+https://github.com/intendednull/yewdux?rev=v0.6.2#a6d8dbf69d472a2d0e82ab70237b16e86865c994"
dependencies = [ dependencies = [
"serde", "serde",
"yew", "yew",
"yew-services",
] ]
[[package]] [[package]]
name = "yewtil" name = "yewtil"
version = "0.3.2" version = "0.4.0"
source = "git+https://github.com/yewstack/yew?rev=246bc59#246bc5960b504258b0603bc76760777e6650c91d" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8543663ac49cd613df079282a1d8bdbdebdad6e02bac229f870fd4237b5d9aaa"
dependencies = [ dependencies = [
"log", "log",
"wasm-bindgen", "wasm-bindgen",
"wasm-bindgen-futures", "wasm-bindgen-futures",
"web-sys",
"yew", "yew",
] ]

View File

@ -13,20 +13,13 @@ crate-type = ["cdylib", "rlib"]
tenebrous-api = { path = "../../api" } tenebrous-api = { path = "../../api" }
[dependencies] [dependencies]
# yew = { version = "0.18" } yew = { version = "0.18" }
# yewtil = {version = "0.4" } yewtil = {version = "0.4" }
# yew-router = {version = "0.15" } yew-router = {version = "0.15" }
# yewdux = {version = "^0.6" } yewdux = { git = "https://github.com/intendednull/yewdux", rev = "v0.6.2"}
yew = { git = "https://github.com/yewstack/yew", rev = "246bc59" }
yew-functional = { git = "https://github.com/yewstack/yew", rev = "246bc59" }
yew-router = { git = "https://github.com/yewstack/yew", rev = "246bc59" }
yew-services = { git = "https://github.com/yewstack/yew", rev = "246bc59" }
yewtil = { git = "https://github.com/yewstack/yew", rev = "246bc59"}
yewdux = { git = "https://github.com/deftsp/yewdux", rev = "dbda686"}
wasm-bindgen = { version = "0.2" } wasm-bindgen = { version = "0.2" }
wasm-bindgen-futures = "0.4" wasm-bindgen-futures = "0.4"
js-sys = "0.3" js-sys = "0.3"
#grpc-web-client = "0.1"
graphql_client = { git = "https://github.com/graphql-rust/graphql-client", branch = "master" } graphql_client = { git = "https://github.com/graphql-rust/graphql-client", branch = "master" }
graphql_client_web = { git = "https://github.com/graphql-rust/graphql-client", branch = "master" } graphql_client_web = { git = "https://github.com/graphql-rust/graphql-client", branch = "master" }
serde = { version = "1.0.67", features = ["derive"] } serde = { version = "1.0.67", features = ["derive"] }

View File

@ -25,20 +25,14 @@ pub enum LoginAction {
} }
pub(crate) type Login = WithDispatch<YewduxLogin>; pub(crate) type Login = WithDispatch<YewduxLogin>;
async fn do_login( async fn do_login(
dispatch: &WebUiDispatcher, dispatch: &WebUiDispatcher,
username: &str, username: &str,
password: &str, password: &str,
) -> Result<(), UiError> { ) -> Result<(), UiError> {
let jwt = api::auth::login(username, password).await?; let jwt = api::auth::login(username, password).await?;
//state.jwt_token = Some(jwt); dispatch.send(Action::Login(jwt));
dispatch.send(Action::UpdateJwt(jwt));
Ok(())
}
async fn do_refresh_jwt(dispatch: &WebUiDispatcher) -> Result<(), UiError> {
let jwt = api::auth::refresh_jwt().await?;
dispatch.send(Action::UpdateJwt(jwt));
Ok(()) Ok(())
} }
@ -78,31 +72,12 @@ impl Component for YewduxLogin {
self.dispatch.neq_assign(Rc::new(dispatch)) self.dispatch.neq_assign(Rc::new(dispatch))
} }
fn rendered(&mut self, first_render: bool) {
if first_render {
//
}
}
fn view(&self) -> Html { fn view(&self) -> Html {
// let do_the_login = self.dispatch.reduce_callback(|state| {
// spawn_local(async move {
// do_login(state, "user", "pw").await;
// });
// });
let do_the_login = self.link.callback(move |e: FocusEvent| { let do_the_login = self.link.callback(move |e: FocusEvent| {
e.prevent_default(); e.prevent_default();
LoginAction::Login LoginAction::Login
}); });
// let refresh_jwt = self.link.callback(move |_| {
// let dispatch = dispatch2.clone();
// spawn_local(async move {
// do_refresh_jwt(&*dispatch).await;
// });
// });
let update_username = self let update_username = self
.link .link
.callback(|e: InputData| LoginAction::UpdateUsername(e.value)); .callback(|e: InputData| LoginAction::UpdateUsername(e.value));

View File

@ -1,11 +1,16 @@
use crate::components::error_message::ErrorMessage; use crate::components::error_message::ErrorMessage;
use crate::components::login::Login; use crate::components::login::Login;
use error::UiError;
use rooms::RoomList; use rooms::RoomList;
use rooms::YewduxRoomList; use rooms::YewduxRoomList;
use state::{Action, AuthState, WebUiDispatcher};
use wasm_bindgen::prelude::*; use wasm_bindgen::prelude::*;
use wasm_bindgen_futures::spawn_local;
use yew::prelude::*; use yew::prelude::*;
use yew_router::prelude::*; use yew_router::prelude::*;
use yew_router::{components::RouterAnchor, prelude::*, switch::Permissive};
use yewdux::prelude::*; use yewdux::prelude::*;
use yewtil::NeqAssign;
pub mod api; pub mod api;
pub mod components; pub mod components;
@ -14,20 +19,20 @@ pub mod grpc;
pub mod rooms; pub mod rooms;
pub mod state; pub mod state;
#[derive(Routable, PartialEq, Clone, Debug)] #[derive(Clone, Debug, Switch)]
pub enum AppRoute { pub enum AppRoute {
#[at("/rooms")] #[to = "/rooms"]
Rooms, Rooms,
#[at("/rooms/{room_id}")] #[to = "/rooms/{room_id}"]
Room { room_id: String }, Room { room_id: String },
#[at("/")] #[to = "/"]
Index, Index,
} }
type AppRouter = Router<AppRoute>; type AppRouter = Router<AppRoute>;
type AppAnchor = Link<AppRoute>; //For rendering clickable links. type AppAnchor = RouterAnchor<AppRoute>; //For rendering clickable links.
fn render_route(routes: &AppRoute) -> Html { fn render_route(routes: AppRoute) -> Html {
match routes { match routes {
AppRoute::Rooms => { AppRoute::Rooms => {
html! { html! {
@ -36,13 +41,12 @@ fn render_route(routes: &AppRoute) -> Html {
} }
AppRoute::Room { room_id } => { AppRoute::Room { room_id } => {
html! { html! {
<div>{"This is the specifi roompage."}</div> <div>{"This is the specific room page."}</div>
} }
} }
AppRoute::Index => { AppRoute::Index => {
html! { html! {
<div> <div>
<Login />
<ErrorMessage /> <ErrorMessage />
<RoomList /> <RoomList />
</div> </div>
@ -51,25 +55,69 @@ fn render_route(routes: &AppRoute) -> Html {
} }
} }
struct App; struct YewduxApp {
link: ComponentLink<YewduxApp>,
dispatch: WebUiDispatcher,
}
impl Component for App { type App = WithDispatch<YewduxApp>;
async fn refresh_jwt(dispatch: &WebUiDispatcher) {
match api::auth::refresh_jwt().await {
Ok(jwt) => {
dispatch.send(Action::Login(jwt));
}
Err(e) => {
web_sys::console::log_1(&e.to_string().into());
dispatch.send(Action::ChangeAuthState(AuthState::NotLoggedIn));
}
}
}
impl Component for YewduxApp {
type Message = (); type Message = ();
type Properties = (); type Properties = WebUiDispatcher;
fn create(_: Self::Properties, _link: ComponentLink<Self>) -> Self { fn create(dispatch: Self::Properties, link: ComponentLink<Self>) -> Self {
Self Self { dispatch, link }
} }
fn update(&mut self, _: Self::Message) -> ShouldRender { fn update(&mut self, _: Self::Message) -> ShouldRender {
false false
} }
fn change(&mut self, _: Self::Properties) -> ShouldRender { fn change(&mut self, dispatch: Self::Properties) -> ShouldRender {
false self.dispatch.neq_assign(dispatch)
}
fn rendered(&mut self, first_render: bool) {
if first_render {
let auth_state = self.dispatch.state().auth_state;
if auth_state == AuthState::RefreshNeeded {
let dispatch = self.dispatch.clone();
spawn_local(async move {
refresh_jwt(&dispatch).await;
});
}
}
} }
fn view(&self) -> Html { fn view(&self) -> Html {
let auth_state = self.dispatch.state().auth_state;
match auth_state {
AuthState::RefreshNeeded => {
html! {
<div>{"Loading..."}</div>
}
}
AuthState::NotLoggedIn => {
html! {
<Login />
}
}
AuthState::LoggedIn => {
html! { html! {
<div> <div>
<div class="alert alert-primary" role="alert"> <div class="alert alert-primary" role="alert">
@ -82,6 +130,8 @@ impl Component for App {
} }
} }
} }
}
}
#[wasm_bindgen(start)] #[wasm_bindgen(start)]
pub fn run_app() { pub fn run_app() {

View File

@ -8,8 +8,22 @@ pub(crate) struct Room {
pub display_name: String, pub display_name: String,
} }
#[derive(Clone, Copy, Eq, PartialEq)]
pub(crate) enum AuthState {
NotLoggedIn,
LoggedIn,
RefreshNeeded,
}
impl Default for AuthState {
fn default() -> Self {
AuthState::RefreshNeeded
}
}
#[derive(Default, Clone)] #[derive(Default, Clone)]
pub(crate) struct WebUiState { pub(crate) struct WebUiState {
pub auth_state: AuthState,
pub jwt_token: Option<String>, pub jwt_token: Option<String>,
pub rooms: Vec<Room>, pub rooms: Vec<Room>,
pub error_messages: Vec<String>, pub error_messages: Vec<String>,
@ -20,6 +34,8 @@ pub(crate) enum Action {
AddRoom(Room), AddRoom(Room),
ErrorMessage(UiError), ErrorMessage(UiError),
ClearErrorMessage, ClearErrorMessage,
ChangeAuthState(AuthState),
Login(String),
} }
impl Reducer for WebUiState { impl Reducer for WebUiState {
@ -32,7 +48,12 @@ impl Reducer for WebUiState {
fn reduce(&mut self, action: Self::Action) -> bool { fn reduce(&mut self, action: Self::Action) -> bool {
match action { match action {
Action::UpdateJwt(jwt_token) => self.jwt_token = Some(jwt_token), Action::UpdateJwt(jwt_token) => self.jwt_token = Some(jwt_token),
Action::Login(jwt_token) => {
self.jwt_token = Some(jwt_token);
self.auth_state = AuthState::LoggedIn;
}
Action::AddRoom(room) => self.rooms.push(room.clone()), Action::AddRoom(room) => self.rooms.push(room.clone()),
Action::ChangeAuthState(auth_state) => self.auth_state = auth_state,
Action::ErrorMessage(error) => self.error_messages.push(error.to_string()), Action::ErrorMessage(error) => self.error_messages.push(error.to_string()),
Action::ClearErrorMessage => { Action::ClearErrorMessage => {
if self.error_messages.len() > 0 { if self.error_messages.len() > 0 {