diff --git a/web/index.html b/web/index.html index edb1ba1..37663ac 100644 --- a/web/index.html +++ b/web/index.html @@ -16,9 +16,13 @@ .error { background-color: red; } -.text_plain { +.view-part-text-plain { white-space: pre-line; } +iframe { + height: 100%; + width: 100%; +} diff --git a/web/src/lib.rs b/web/src/lib.rs index b8d0ede..860f209 100644 --- a/web/src/lib.rs +++ b/web/src/lib.rs @@ -3,8 +3,8 @@ // but some rules are too "annoying" or are not applicable for your case.) #![allow(clippy::wildcard_imports)] -use log::{debug, error, info, Level}; -use notmuch::{Content, Part, SearchSummary, ThreadNode, ThreadSet}; +use log::{debug, error, info, warn, Level}; +use notmuch::{Content, Part, SearchSummary, Thread, ThreadNode, ThreadSet}; use seed::{prelude::*, *}; // ------ ------ @@ -13,14 +13,34 @@ use seed::{prelude::*, *}; // `init` describes what should happen when your app started. fn init(url: Url, orders: &mut impl Orders) -> Model { + warn!("init called"); log!(url); - orders.subscribe(|_: subs::UrlChanged| info!("url changed!")); - orders - .skip() - .perform_cmd(async { Msg::SearchResult(search_request("*").await) }); + let mut url = url.clone(); + let mut query = "".to_string(); + let hpp = url.next_hash_path_part(); + log!(hpp); + match hpp { + Some("t") => { + let tid = url.next_hash_path_part().unwrap_or("").to_string(); + orders.send_msg(Msg::ShowRequest(tid)); + } + Some("s") => { + query = url.next_hash_path_part().unwrap_or("").to_string(); + orders.send_msg(Msg::SearchRequest(query.clone())); + } + p => { + log!(p); + orders.send_msg(Msg::SearchRequest("".to_string())); + } + }; + orders.subscribe(|uc: subs::UrlChanged| { + info!("uc {:#?}", uc); + }); + + info!("init query '{}'", query); Model { context: Context::None, - query: "".to_string(), + query, } } @@ -57,32 +77,34 @@ enum Msg { fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders) { match msg { Msg::Noop => {} + Msg::SearchRequest(query) => { model.query = query.clone(); + let url = Url::new().set_hash_path(["s", &query]); + orders.request_url(url); orders .skip() .perform_cmd(async move { Msg::SearchResult(search_request(&query).await) }); } - Msg::SearchResult(Ok(response_data)) => { debug!("fetch ok {:#?}", response_data); model.context = Context::Search(response_data); } - Msg::SearchResult(Err(fetch_error)) => { error!("fetch failed {:?}", fetch_error); } - Msg::ShowRequest(query) => { + + Msg::ShowRequest(tid) => { + let url = Url::new().set_hash_path(["t", &tid]); + orders.request_url(url); orders .skip() - .perform_cmd(async move { Msg::ShowResult(show_request(&query).await) }); + .perform_cmd(async move { Msg::ShowResult(show_request(&tid).await) }); } - Msg::ShowResult(Ok(response_data)) => { debug!("fetch ok {:#?}", response_data); model.context = Context::Thread(response_data); } - Msg::ShowResult(Err(fetch_error)) => { error!("fetch failed {:?}", fetch_error); } @@ -90,6 +112,7 @@ fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders) { } async fn search_request(query: &str) -> fetch::Result { + info!("making search request for '{}'", query); Request::new(api::search(query)) .method(Method::Get) .fetch() @@ -100,20 +123,20 @@ async fn search_request(query: &str) -> fetch::Result { } mod api { - const BASE_URL: &str = "http://nixos-07:9345"; + const BASE_URL: &str = "/api"; pub fn search(query: &str) -> String { format!("{}/search/{}", BASE_URL, query) } - pub fn show(query: &str) -> String { - format!("{}/show/{}", BASE_URL, query) + pub fn show(tid: &str) -> String { + format!("{}/show/{}", BASE_URL, tid) } pub fn original(message_id: &str) -> String { format!("{}/original/{}", BASE_URL, message_id) } } -async fn show_request(query: &str) -> fetch::Result { - Request::new(api::show(query)) +async fn show_request(tid: &str) -> fetch::Result { + Request::new(api::show(tid)) .method(Method::Get) .fetch() .await? @@ -180,11 +203,7 @@ fn view_part(part: &Part) -> Node { "text/plain" => view_text_plain(&part.content), "text/html" => { if let Some(Content::String(html)) = &part.content { - return div![ - C!["view-part-text-html"], - div!["TEST"], - iframe![Node::from_html(None, &html)] - ]; + return div![C!["view-part-text-html"], div!["TEST"], raw![&html]]; } else { div![ C!["error"], @@ -244,10 +263,12 @@ fn first_subject(thread: &ThreadNode) -> Option { None } -fn view_search_results(search_results: &SearchSummary) -> Node { +fn view_search_results(query: &str, search_results: &SearchSummary) -> Node { + seed::document().set_title(&format!("lb: {}", query)); let rows = search_results.0.iter().map(|r| { let tid = r.thread.clone(); tr![ + td![], td![ &r.authors, IF!(r.total>1 => small![" ", r.total.to_string()]), @@ -258,7 +279,10 @@ fn view_search_results(search_results: &SearchSummary) -> Node { ev(Ev::Click, move |_| Msg::ShowRequest(tid)), ] }); - div![table![tr![th!["From"], th!["Subject"], th!["Date"]], rows]] + div![table![ + tr![th!["tid"], th!["From"], th!["Subject"], th!["Date"]], + rows + ]] } fn view_thread(thread_set: &ThreadSet) -> Node { @@ -266,14 +290,46 @@ fn view_thread(thread_set: &ThreadSet) -> Node { let thread = &thread_set.0[0]; assert_eq!(thread.0.len(), 1); let thread_node = &thread.0[0]; + let subject = first_subject(&thread_node).unwrap_or("".to_string()); + seed::document().set_title(&subject); div![ - h1![first_subject(&thread_node)], + h1![subject], a![ attrs! {At::Href=>api::original(&thread_node.0.as_ref().expect("message missing").id)}, "Original" ], view_message(&thread_node), - pre!["Add zippy for debug dump"] /* pre![format!("Thread: {:#?}", thread_set).replace(" ", " ")] */ + pre![ + "Add zippy for debug dump", + view_debug_thread_set(thread_set) + ] /* pre![format!("Thread: {:#?}", thread_set).replace(" ", " ")] */ + ] +} + +fn view_debug_thread_set(thread_set: &ThreadSet) -> Node { + ul![thread_set + .0 + .iter() + .enumerate() + .map(|(i, t)| { li!["t", i, ": ", view_debug_thread(t),] })] +} +fn view_debug_thread(thread: &Thread) -> Node { + ul![thread + .0 + .iter() + .enumerate() + .map(|(i, tn)| { li!["tn", i, ": ", view_debug_thread_node(tn),] })] +} + +fn view_debug_thread_node(thread_node: &ThreadNode) -> Node { + ul![ + IF!(thread_node.0.is_some()=>li!["tn id:", &thread_node.0.as_ref().unwrap().id]), + thread_node.1.iter().enumerate().map(|(i, tn)| li![ + "tn", + i, + ": ", + view_debug_thread_node(tn) + ]) ] } @@ -307,7 +363,7 @@ fn view(model: &Model) -> Node { let content = match &model.context { Context::None => div![h1!["Loading"]], Context::Thread(thread_set) => view_thread(thread_set), - Context::Search(search_results) => view_search_results(search_results), + Context::Search(search_results) => view_search_results(&model.query, search_results), }; div![view_header(&model.query), content] }