Web API, Web UI #86
|
@ -3481,6 +3481,7 @@ dependencies = [
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"serde",
|
"serde",
|
||||||
"tenebrous-api",
|
"tenebrous-api",
|
||||||
|
"thiserror",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
"wasm-bindgen-futures",
|
"wasm-bindgen-futures",
|
||||||
"web-sys",
|
"web-sys",
|
||||||
|
|
|
@ -25,6 +25,7 @@ web-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"] }
|
||||||
|
thiserror = "1.0"
|
||||||
|
|
||||||
# hopefully we can add grpc-web later instead of graphql.
|
# hopefully we can add grpc-web later instead of graphql.
|
||||||
# prost = { version = "0.7.0", default-features = false }
|
# prost = { version = "0.7.0", default-features = false }
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
use graphql_client::web::Client;
|
use graphql_client::web::Client;
|
||||||
use graphql_client::web::ClientError;
|
|
||||||
use graphql_client::GraphQLQuery;
|
use graphql_client::GraphQLQuery;
|
||||||
|
use graphql_client_web::Response;
|
||||||
|
|
||||||
|
use super::ResponseExt;
|
||||||
|
use crate::error::UiError;
|
||||||
|
|
||||||
#[derive(GraphQLQuery)]
|
#[derive(GraphQLQuery)]
|
||||||
#[graphql(
|
#[graphql(
|
||||||
|
@ -22,7 +25,7 @@ pub async fn get_user_variable(
|
||||||
room_id: &str,
|
room_id: &str,
|
||||||
user_id: &str,
|
user_id: &str,
|
||||||
variable_name: &str,
|
variable_name: &str,
|
||||||
) -> Result<i64, ClientError> {
|
) -> Result<i64, UiError> {
|
||||||
let client = Client::new("http://localhost:10000/graphql");
|
let client = Client::new("http://localhost:10000/graphql");
|
||||||
let variables = get_user_variable::Variables {
|
let variables = get_user_variable::Variables {
|
||||||
room_id: room_id.to_owned(),
|
room_id: room_id.to_owned(),
|
||||||
|
@ -30,27 +33,20 @@ pub async fn get_user_variable(
|
||||||
variable: variable_name.to_owned(),
|
variable: variable_name.to_owned(),
|
||||||
};
|
};
|
||||||
|
|
||||||
//TODO don't unwrap() option. map to err instead.
|
|
||||||
let response = client.call(GetUserVariable, variables).await?;
|
let response = client.call(GetUserVariable, variables).await?;
|
||||||
let response: graphql_client_web::Response<get_user_variable::ResponseData> = response;
|
let response: graphql_client_web::Response<get_user_variable::ResponseData> = response;
|
||||||
let value = response.data.map(|d| d.variable.value).unwrap();
|
Ok(response.data()?.variable.value)
|
||||||
Ok(value)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn rooms_for_user(
|
pub async fn rooms_for_user(
|
||||||
user_id: &str,
|
user_id: &str,
|
||||||
) -> Result<Vec<rooms_for_user::RoomsForUserUserRoomsRooms>, ClientError> {
|
) -> Result<Vec<rooms_for_user::RoomsForUserUserRoomsRooms>, UiError> {
|
||||||
let client = Client::new("http://localhost:10000/graphql");
|
let client = Client::new("http://localhost:10000/graphql");
|
||||||
let variables = rooms_for_user::Variables {
|
let variables = rooms_for_user::Variables {
|
||||||
user_id: user_id.to_owned(),
|
user_id: user_id.to_owned(),
|
||||||
};
|
};
|
||||||
|
|
||||||
//TODO don't unwrap() option. map to err instead.
|
|
||||||
let response = client.call(RoomsForUser, variables).await?;
|
let response = client.call(RoomsForUser, variables).await?;
|
||||||
let response: graphql_client_web::Response<rooms_for_user::ResponseData> = response;
|
let response: Response<rooms_for_user::ResponseData> = response;
|
||||||
let rooms = response
|
Ok(response.data()?.user_rooms.rooms)
|
||||||
.data
|
|
||||||
.map(|d| d.user_rooms.rooms)
|
|
||||||
.unwrap_or_default();
|
|
||||||
Ok(rooms)
|
|
||||||
}
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
use graphql_client_web::Response;
|
||||||
|
|
||||||
|
use crate::error::UiError;
|
||||||
|
|
||||||
|
/// Extensions to the GraphQL web response type to add convenience,
|
||||||
|
/// particularly when working with errors.
|
||||||
|
trait ResponseExt<T> {
|
||||||
|
/// Get the data from the response, or gather all server-side
|
||||||
|
/// errors into a UiError variant.
|
||||||
|
fn data(self) -> Result<T, UiError>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> ResponseExt<T> for Response<T> {
|
||||||
|
fn data(self) -> Result<T, UiError> {
|
||||||
|
let data = self.data;
|
||||||
|
let errors = self.errors;
|
||||||
|
|
||||||
|
let data = data.ok_or_else(|| {
|
||||||
|
UiError::ApiError(
|
||||||
|
errors
|
||||||
|
.map(|errors| {
|
||||||
|
errors
|
||||||
|
.into_iter()
|
||||||
|
.map(|e| e.to_string())
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(",")
|
||||||
|
})
|
||||||
|
.unwrap_or("unknown error".into()),
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
Ok(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod dicebot;
|
|
@ -0,0 +1,12 @@
|
||||||
|
use graphql_client_web::ClientError;
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
#[derive(Error, Debug)]
|
||||||
|
pub enum UiError {
|
||||||
|
#[error("api client error: {0}")]
|
||||||
|
ApiClientError(#[from] ClientError),
|
||||||
|
|
||||||
|
/// General API error, collecting errors from graphql server.
|
||||||
|
#[error("error: {0}")]
|
||||||
|
ApiError(String),
|
||||||
|
}
|
|
@ -3,7 +3,8 @@ use wasm_bindgen::prelude::*;
|
||||||
use yew::prelude::*;
|
use yew::prelude::*;
|
||||||
use yew_router::{components::RouterAnchor, prelude::*};
|
use yew_router::{components::RouterAnchor, prelude::*};
|
||||||
|
|
||||||
pub mod graphql;
|
pub mod api;
|
||||||
|
pub mod error;
|
||||||
pub mod grpc;
|
pub mod grpc;
|
||||||
pub mod rooms;
|
pub mod rooms;
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
|
use crate::api;
|
||||||
|
use crate::error::UiError;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen_futures::spawn_local;
|
||||||
use wasm_bindgen::JsValue;
|
|
||||||
use wasm_bindgen_futures::{future_to_promise, spawn_local};
|
|
||||||
use web_sys::console;
|
use web_sys::console;
|
||||||
use yew::prelude::*;
|
use yew::prelude::*;
|
||||||
use yewdux::prelude::*;
|
use yewdux::prelude::*;
|
||||||
|
@ -59,10 +59,8 @@ fn view_room(room: &Room) -> Html {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn do_things(dispatch: &RoomListDispatch) {
|
async fn load_rooms(dispatch: &RoomListDispatch) -> Result<(), UiError> {
|
||||||
let rooms = crate::graphql::rooms_for_user("@projectmoon:agnos.is")
|
let rooms = api::dicebot::rooms_for_user("@projectmoon:agnos.is").await?;
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
for room in rooms {
|
for room in rooms {
|
||||||
dispatch.send(Action::AddRoom(Room {
|
dispatch.send(Action::AddRoom(Room {
|
||||||
|
@ -70,6 +68,8 @@ async fn do_things(dispatch: &RoomListDispatch) {
|
||||||
display_name: room.display_name,
|
display_name: room.display_name,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Component for YewduxRoomList {
|
impl Component for YewduxRoomList {
|
||||||
|
@ -95,7 +95,12 @@ impl Component for YewduxRoomList {
|
||||||
let dispatch = dispatch.clone();
|
let dispatch = dispatch.clone();
|
||||||
|
|
||||||
spawn_local(async move {
|
spawn_local(async move {
|
||||||
do_things(&*dispatch).await;
|
//TODO make macro to report errors in some common way:
|
||||||
|
//handle_errors!(do_things(&*dispatch).await)
|
||||||
|
match load_rooms(&*dispatch).await {
|
||||||
|
Err(e) => console::log_1(&format!("Error: {:?}", e).into()),
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue