From 6eca4503466cd48d656840d4e061facd9e3554d0 Mon Sep 17 00:00:00 2001 From: projectmoon Date: Sat, 5 Jun 2021 21:42:13 +0000 Subject: [PATCH] Web UI with a functional async-await boundary! --- .gitignore | 1 + Cargo.lock | 3 + web-ui/crate/Cargo.toml | 3 + web-ui/crate/src/lib.rs | 109 ++++++++++++++++-------------------- web-ui/crate/src/oaths.rs | 77 -------------------------- web-ui/crate/src/rooms.rs | 113 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 167 insertions(+), 139 deletions(-) delete mode 100644 web-ui/crate/src/oaths.rs create mode 100644 web-ui/crate/src/rooms.rs diff --git a/.gitignore b/.gitignore index 2429ce1..86998ba 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,4 @@ bigboy .tmp* node_modules dist/ +yarn-error.log diff --git a/Cargo.lock b/Cargo.lock index cd84596..dfc1478 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3341,7 +3341,10 @@ name = "tenebrous-web-ui" version = "0.1.0" dependencies = [ "grpc-web-client", + "js-sys", "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", "yew", "yew-router", "yewdux", diff --git a/web-ui/crate/Cargo.toml b/web-ui/crate/Cargo.toml index dc064f4..8fc564a 100644 --- a/web-ui/crate/Cargo.toml +++ b/web-ui/crate/Cargo.toml @@ -15,7 +15,10 @@ yewtil = {version = "0.3" } yew-router = {version = "0.14" } yewdux = {version = "^0.6" } wasm-bindgen = { version = "0.2" } +wasm-bindgen-futures = "0.4" +js-sys = "0.3" grpc-web-client = "0.1" +web-sys = "0.3" # hopefully we can add grpc-web later instead of graphql. # prost = { version = "0.7.0", default-features = false } diff --git a/web-ui/crate/src/lib.rs b/web-ui/crate/src/lib.rs index aeff7c9..1504519 100644 --- a/web-ui/crate/src/lib.rs +++ b/web-ui/crate/src/lib.rs @@ -1,98 +1,84 @@ -use oaths::OathsList; +use rooms::RoomList; use wasm_bindgen::prelude::*; use yew::prelude::*; use yew_router::{components::RouterAnchor, prelude::*}; pub mod grpc; -pub mod oaths; +pub mod rooms; #[derive(Switch, Clone, Debug)] pub enum AppRoute { - #[to = "/oaths"] - Oaths, - #[to = "/commitments"] - Commitments, - #[to = "/studies"] - Studies, - #[to = "/divination"] - RunicDivination, + #[to = "/rooms"] + Rooms, + #[to = "/rooms/{room_id}"] + Room(String), #[to = "/"] Index, } type AppRouter = Router; -type AppAnchor = RouterAnchor; +type AppAnchor = RouterAnchor; //For rendering clickable links. fn render_route(switch: AppRoute) -> Html { match switch { - AppRoute::Oaths => { + AppRoute::Rooms => { html! { - + } } - AppRoute::Commitments => { + AppRoute::Room(room_id) => { html! { -
{"This is the commitments page."}
- } - } - AppRoute::Studies => { - html! { -
{"This is the studies page."}
- } - } - AppRoute::RunicDivination => { - html! { -
{"This is the runic divination page."}
+
{"This is the specifi roompage."}
} } AppRoute::Index => { html! { -
{"This is the index."}
+ } } } } -struct AppMenu; +// struct AppMenu; -impl Component for AppMenu { - type Message = (); - type Properties = (); +// impl Component for AppMenu { +// type Message = (); +// type Properties = (); - fn create(_: Self::Properties, _link: ComponentLink) -> Self { - Self - } +// fn create(_: Self::Properties, _link: ComponentLink) -> Self { +// Self +// } - fn update(&mut self, _msg: Self::Message) -> ShouldRender { - false - } +// fn update(&mut self, _msg: Self::Message) -> ShouldRender { +// false +// } - fn change(&mut self, _: Self::Properties) -> ShouldRender { - false - } +// fn change(&mut self, _: Self::Properties) -> ShouldRender { +// false +// } - fn view(&self) -> Html { - html! { -
    -
  • - {"Home"} -
  • -
  • - {"Oaths"} -
  • -
  • - {"Commitments"} -
  • -
  • - {"Studies"} -
  • -
  • - {"Runic Divination"} -
  • -
- } - } -} +// fn view(&self) -> Html { +// html! { +//
    +//
  • +// {"Home"} +//
  • +//
  • +// {"Oaths"} +//
  • +//
  • +// {"Commitments"} +//
  • +//
  • +// {"Studies"} +//
  • +//
  • +// {"Runic Divination"} +//
  • +//
+// } +// } +// } struct App; @@ -116,7 +102,6 @@ impl Component for App { html! {
{"Hello World"} -
} diff --git a/web-ui/crate/src/oaths.rs b/web-ui/crate/src/oaths.rs deleted file mode 100644 index 8b839ab..0000000 --- a/web-ui/crate/src/oaths.rs +++ /dev/null @@ -1,77 +0,0 @@ -use yew::prelude::*; -use yewdux::prelude::*; -use yewtil::NeqAssign; - -struct Oaths; - -#[derive(Clone)] -struct Oath { - title: String, - content: String, -} - -#[derive(Default, Clone)] -pub(crate) struct OathState { - oaths: Vec, -} - -type OathDispatch = DispatchProps>; - -//Oaths list -pub(crate) struct StatefulOathsList { - dispatch: OathDispatch, -} - -pub(crate) type OathsList = WithDispatch; - -fn view_oath(oath: &Oath) -> Html { - html! { -
-
{oath.title.clone()}
-
{oath.content.clone()}
-
- } -} - -impl Component for StatefulOathsList { - type Message = (); - type Properties = OathDispatch; - - fn create(dispatch: Self::Properties, _link: ComponentLink) -> Self { - Self { dispatch } - } - - fn update(&mut self, _msg: Self::Message) -> ShouldRender { - false - } - - fn change(&mut self, dispatch: Self::Properties) -> ShouldRender { - self.dispatch.neq_assign(dispatch) - } - - fn view(&self) -> Html { - let add_oath = self.dispatch.reduce_callback(|s| { - s.oaths.push(Oath { - title: "yolo".to_string(), - content: "nolo".to_string(), - }) - }); - - html! { -
- -
    - { - for self.dispatch.state().oaths.iter().map(|oath| { - view_oath(oath) - }) - } -
-
- } - } -} - -//New oath form - -//Edit oath diff --git a/web-ui/crate/src/rooms.rs b/web-ui/crate/src/rooms.rs new file mode 100644 index 0000000..cbc89cb --- /dev/null +++ b/web-ui/crate/src/rooms.rs @@ -0,0 +1,113 @@ +use std::sync::Arc; +use wasm_bindgen::prelude::*; +use wasm_bindgen::JsValue; +use wasm_bindgen_futures::{future_to_promise, spawn_local}; +use web_sys::console; +use yew::prelude::*; +use yewdux::prelude::*; +use yewtil::NeqAssign; + +#[derive(Clone)] +pub(crate) struct Room { + room_id: String, + display_name: String, +} + +#[derive(Default, Clone)] +pub(crate) struct RoomListState { + rooms: Vec, +} + +pub(crate) enum Action { + AddRoom(Room), +} + +impl Reducer for RoomListState { + type Action = Action; + + fn new() -> Self { + Self { rooms: vec![] } + } + + fn reduce(&mut self, action: Self::Action) -> bool { + match action { + Action::AddRoom(room) => { + self.rooms.push(room.clone()); + true + } + } + } +} + +type RoomListDispatch = DispatchProps>; + +//Oaths list +#[doc(hidden)] +pub(crate) struct YewduxRoomList { + dispatch: RoomListDispatch, + link: ComponentLink, +} + +pub(crate) type RoomList = WithDispatch; + +fn view_room(room: &Room) -> Html { + html! { +
+
{room.room_id.clone()}
+
{room.display_name.clone()}
+
+ } +} + +async fn do_things(dispatch: &RoomListDispatch) { + dispatch.send(Action::AddRoom(Room { + room_id: "asdf".into(), + display_name: "adslkjg".into(), + })); +} + +impl Component for YewduxRoomList { + type Message = (); + type Properties = RoomListDispatch; + + fn create(dispatch: Self::Properties, link: ComponentLink) -> Self { + Self { dispatch, link } + } + + fn update(&mut self, _msg: Self::Message) -> ShouldRender { + false + } + + fn change(&mut self, dispatch: Self::Properties) -> ShouldRender { + self.dispatch.neq_assign(dispatch) + } + + fn view(&self) -> Html { + let dispatch = Arc::new(self.dispatch.clone()); + + let the_future = self.link.callback(move |_| { + let dispatch = dispatch.clone(); + + spawn_local(async move { + do_things(&*dispatch).await; + }); + }); + + html! { +
+ +
    + { + for self.dispatch.state().rooms.iter().map(|oath| { + view_room(oath) + }) + } +
+
+ } + } +} + +//New oath form + +//Edit oath