Web API, Web UI #86
|
@ -3578,6 +3578,7 @@ dependencies = [
|
||||||
"graphql_client_web",
|
"graphql_client_web",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"serde",
|
"serde",
|
||||||
|
"serde_json",
|
||||||
"tenebrous-api",
|
"tenebrous-api",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
|
|
|
@ -30,6 +30,7 @@ js-sys = "0.3"
|
||||||
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"] }
|
||||||
|
serde_json = {version = "1.0" }
|
||||||
thiserror = "1.0"
|
thiserror = "1.0"
|
||||||
|
|
||||||
[dependencies.web-sys]
|
[dependencies.web-sys]
|
||||||
|
|
|
@ -17,21 +17,25 @@ async fn make_request(request: Request) -> Result<JsValue, UiError> {
|
||||||
let resp: Response = resp_value.dyn_into().unwrap();
|
let resp: Response = resp_value.dyn_into().unwrap();
|
||||||
|
|
||||||
let json = JsFuture::from(resp.json()?).await?;
|
let json = JsFuture::from(resp.json()?).await?;
|
||||||
|
console::log_1(&json);
|
||||||
Ok(json)
|
Ok(json)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn fetch_jwt() -> Result<String, UiError> {
|
pub async fn login(username: &str, password: &str) -> Result<String, UiError> {
|
||||||
let mut opts = RequestInit::new();
|
let mut opts = RequestInit::new();
|
||||||
opts.method("POST");
|
opts.method("POST");
|
||||||
opts.mode(RequestMode::Cors);
|
opts.mode(RequestMode::Cors);
|
||||||
opts.credentials(RequestCredentials::Include);
|
opts.credentials(RequestCredentials::Include);
|
||||||
|
|
||||||
opts.body(Some(&JsValue::from_str(
|
let body = JsValue::from_str(
|
||||||
r#"
|
&serde_json::json!({
|
||||||
{ "username": "@projectmoon:agnos.is", "password": "lolol" }
|
"username": username,
|
||||||
"#,
|
"password": password
|
||||||
)));
|
})
|
||||||
|
.to_string(),
|
||||||
|
);
|
||||||
|
|
||||||
|
opts.body(Some(&body));
|
||||||
let url = format!("http://localhost:10000/login");
|
let url = format!("http://localhost:10000/login");
|
||||||
|
|
||||||
let request = Request::new_with_str_and_init(&url, &opts)?;
|
let request = Request::new_with_str_and_init(&url, &opts)?;
|
||||||
|
@ -59,7 +63,6 @@ pub async fn refresh_jwt() -> Result<String, UiError> {
|
||||||
|
|
||||||
//TODO don't unwrap the response. OR... change it so we have a standard response.
|
//TODO don't unwrap the response. OR... change it so we have a standard response.
|
||||||
let response = make_request(request).await?;
|
let response = make_request(request).await?;
|
||||||
console::log_1(&response);
|
|
||||||
let response: LoginResponse = response.into_serde().unwrap();
|
let response: LoginResponse = response.into_serde().unwrap();
|
||||||
|
|
||||||
Ok(response.jwt_token)
|
Ok(response.jwt_token)
|
||||||
|
|
|
@ -0,0 +1,137 @@
|
||||||
|
use crate::error::UiError;
|
||||||
|
use crate::state::{Action, Room, WebUiDispatcher};
|
||||||
|
use crate::{api, state::WebUiState};
|
||||||
|
use std::sync::Arc;
|
||||||
|
use wasm_bindgen_futures::spawn_local;
|
||||||
|
use web_sys::console;
|
||||||
|
use web_sys::FocusEvent;
|
||||||
|
use yew::prelude::*;
|
||||||
|
use yewdux::dispatch::Dispatcher;
|
||||||
|
use yewdux::prelude::*;
|
||||||
|
use yewtil::NeqAssign;
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub(crate) struct YewduxLogin {
|
||||||
|
dispatch: Arc<WebUiDispatcher>,
|
||||||
|
link: ComponentLink<YewduxLogin>,
|
||||||
|
username: String,
|
||||||
|
password: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum LoginAction {
|
||||||
|
UpdateUsername(String),
|
||||||
|
UpdatePassword(String),
|
||||||
|
Login,
|
||||||
|
Noop,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) type Login = WithDispatch<YewduxLogin>;
|
||||||
|
async fn do_login(
|
||||||
|
dispatch: &WebUiDispatcher,
|
||||||
|
username: &str,
|
||||||
|
password: &str,
|
||||||
|
) -> Result<(), UiError> {
|
||||||
|
let jwt = api::auth::login(username, password).await?;
|
||||||
|
//state.jwt_token = Some(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(())
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Component for YewduxLogin {
|
||||||
|
type Message = LoginAction;
|
||||||
|
type Properties = WebUiDispatcher;
|
||||||
|
|
||||||
|
fn create(dispatch: Self::Properties, link: ComponentLink<Self>) -> Self {
|
||||||
|
Self {
|
||||||
|
dispatch: Arc::new(dispatch),
|
||||||
|
link,
|
||||||
|
username: "".to_string(),
|
||||||
|
password: "".to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update(&mut self, action: Self::Message) -> ShouldRender {
|
||||||
|
match action {
|
||||||
|
LoginAction::UpdateUsername(username) => self.username = username,
|
||||||
|
LoginAction::UpdatePassword(password) => self.password = password,
|
||||||
|
LoginAction::Login => {
|
||||||
|
let dispatch = self.dispatch.clone();
|
||||||
|
let username = self.username.clone();
|
||||||
|
let password = self.password.clone();
|
||||||
|
|
||||||
|
spawn_local(async move {
|
||||||
|
do_login(&*dispatch, &username, &password).await;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
};
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn change(&mut self, dispatch: Self::Properties) -> ShouldRender {
|
||||||
|
self.dispatch.neq_assign(Arc::new(dispatch))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rendered(&mut self, first_render: bool) {
|
||||||
|
if first_render {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn view(&self) -> Html {
|
||||||
|
let dispatch = Arc::new(self.dispatch.clone());
|
||||||
|
let dispatch2 = dispatch.clone();
|
||||||
|
|
||||||
|
// 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| {
|
||||||
|
e.prevent_default();
|
||||||
|
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
|
||||||
|
.link
|
||||||
|
.callback(|e: InputData| LoginAction::UpdateUsername(e.value));
|
||||||
|
|
||||||
|
let update_password = self
|
||||||
|
.link
|
||||||
|
.callback(|e: InputData| LoginAction::UpdatePassword(e.value));
|
||||||
|
|
||||||
|
html! {
|
||||||
|
<div>
|
||||||
|
<form onsubmit=do_the_login>
|
||||||
|
<label for="username">{"Username:"}</label>
|
||||||
|
<input oninput=update_username id="username" name="username" type="text" placeholder="Username" />
|
||||||
|
<label for="password">{"Password:"}</label>
|
||||||
|
<input oninput=update_password id="password" name="password" type="password" placeholder="Password" />
|
||||||
|
<input type="submit" value="Log In" />
|
||||||
|
</form>
|
||||||
|
//<button onclick=refresh_jwt>{ "Refresh JWT" }</button>
|
||||||
|
<div>
|
||||||
|
{ "Current JWT: " }
|
||||||
|
{ self.dispatch.state().jwt_token.as_ref().unwrap_or(&"[not set]".to_string()) }
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn destroy(&mut self) {}
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
pub mod login;
|
|
@ -15,6 +15,9 @@ pub enum UiError {
|
||||||
|
|
||||||
#[error("error: {0}")]
|
#[error("error: {0}")]
|
||||||
JsError(String),
|
JsError(String),
|
||||||
|
|
||||||
|
#[error("(de)serialization error: {0}")]
|
||||||
|
SerdeError(#[from] serde_json::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<wasm_bindgen::JsValue> for UiError {
|
impl From<wasm_bindgen::JsValue> for UiError {
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use crate::components::login::Login;
|
||||||
use rooms::RoomList;
|
use rooms::RoomList;
|
||||||
use rooms::YewduxRoomList;
|
use rooms::YewduxRoomList;
|
||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen::prelude::*;
|
||||||
|
@ -6,6 +7,7 @@ use yew_router::prelude::*;
|
||||||
use yewdux::prelude::*;
|
use yewdux::prelude::*;
|
||||||
|
|
||||||
pub mod api;
|
pub mod api;
|
||||||
|
pub mod components;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod grpc;
|
pub mod grpc;
|
||||||
pub mod rooms;
|
pub mod rooms;
|
||||||
|
@ -38,7 +40,10 @@ fn render_route(routes: &AppRoute) -> Html {
|
||||||
}
|
}
|
||||||
AppRoute::Index => {
|
AppRoute::Index => {
|
||||||
html! {
|
html! {
|
||||||
|
<div>
|
||||||
|
<Login />
|
||||||
<RoomList />
|
<RoomList />
|
||||||
|
</div>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,12 +44,6 @@ async fn load_rooms(dispatch: &WebUiDispatcher) -> Result<(), UiError> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn do_jwt_stuff(dispatch: &WebUiDispatcher) -> Result<(), UiError> {
|
|
||||||
let jwt = api::auth::fetch_jwt().await?;
|
|
||||||
dispatch.send(Action::UpdateJwt(jwt));
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn do_refresh_jwt(dispatch: &WebUiDispatcher) -> Result<(), UiError> {
|
async fn do_refresh_jwt(dispatch: &WebUiDispatcher) -> Result<(), UiError> {
|
||||||
let jwt = api::auth::refresh_jwt().await?;
|
let jwt = api::auth::refresh_jwt().await?;
|
||||||
dispatch.send(Action::UpdateJwt(jwt));
|
dispatch.send(Action::UpdateJwt(jwt));
|
||||||
|
@ -105,13 +99,6 @@ impl Component for YewduxRoomList {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
let jwt_update = self.link.callback(move |_| {
|
|
||||||
let dispatch = dispatch2.clone();
|
|
||||||
spawn_local(async move {
|
|
||||||
do_jwt_stuff(&*dispatch).await;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
let refresh_jwt = self.link.callback(move |_| {
|
let refresh_jwt = self.link.callback(move |_| {
|
||||||
let dispatch = dispatch3.clone();
|
let dispatch = dispatch3.clone();
|
||||||
spawn_local(async move {
|
spawn_local(async move {
|
||||||
|
@ -121,10 +108,8 @@ impl Component for YewduxRoomList {
|
||||||
|
|
||||||
html! {
|
html! {
|
||||||
<div>
|
<div>
|
||||||
<button onclick=the_future>{ "Add Room" }</button>
|
<button onclick=the_future>{ "Fetch Rooms" }</button>
|
||||||
<button onclick=jwt_update>{ "Fetch JWT" }</button>
|
|
||||||
<button onclick=refresh_jwt>{ "Refresh JWT" }</button>
|
<button onclick=refresh_jwt>{ "Refresh JWT" }</button>
|
||||||
<div> { "Current JWT: " } { self.dispatch.state().jwt_token.as_ref().unwrap_or(&"[not set]".to_string()) }</div>
|
|
||||||
<ul>
|
<ul>
|
||||||
{
|
{
|
||||||
for self.dispatch.state().rooms.iter().map(|room| {
|
for self.dispatch.state().rooms.iter().map(|room| {
|
||||||
|
|
Loading…
Reference in New Issue