also resolve articles/instances on search page

This commit is contained in:
Felix Ableitner 2024-02-01 12:52:55 +01:00
parent 1dc984025a
commit 862297638f
4 changed files with 50 additions and 25 deletions

View File

@ -216,15 +216,9 @@ pub(in crate::backend::api) async fn fork_article(
pub(super) async fn resolve_article( pub(super) async fn resolve_article(
Query(query): Query<ResolveObject>, Query(query): Query<ResolveObject>,
data: Data<MyDataHandle>, data: Data<MyDataHandle>,
) -> MyResult<Json<ArticleView>> { ) -> MyResult<Json<DbArticle>> {
let article: DbArticle = ObjectId::from(query.id).dereference(&data).await?; let article = ObjectId::from(query.id).dereference(&data).await?;
let edits = DbEdit::read_for_article(&article, &data.db_connection)?; Ok(Json(article))
let latest_version = edits.last().unwrap().hash.clone();
Ok(Json(ArticleView {
article,
edits,
latest_version,
}))
} }
/// Search articles for matching title or body text. /// Search articles for matching title or body text.

View File

@ -42,7 +42,6 @@ pub(super) async fn resolve_instance(
Query(query): Query<ResolveObject>, Query(query): Query<ResolveObject>,
data: Data<MyDataHandle>, data: Data<MyDataHandle>,
) -> MyResult<Json<DbInstance>> { ) -> MyResult<Json<DbInstance>> {
// TODO: workaround because axum makes it hard to have multiple routes on /
let instance: DbInstance = ObjectId::from(query.id).dereference(&data).await?; let instance: DbInstance = ObjectId::from(query.id).dereference(&data).await?;
Ok(Json(instance)) Ok(Json(instance))
} }

View File

@ -156,7 +156,7 @@ impl ApiClient {
Ok(handle_json_res(req).await.unwrap()) Ok(handle_json_res(req).await.unwrap())
} }
pub async fn resolve_article(&self, id: Url) -> MyResult<ArticleView> { pub async fn resolve_article(&self, id: Url) -> MyResult<DbArticle> {
let resolve_object = ResolveObject { id }; let resolve_object = ResolveObject { id };
self.get_query("article/resolve", Some(resolve_object)) self.get_query("article/resolve", Some(resolve_object))
.await .await

View File

@ -1,34 +1,66 @@
use crate::common::SearchArticleData; use crate::common::{DbArticle, DbInstance, SearchArticleData};
use crate::frontend::app::GlobalState; use crate::frontend::app::GlobalState;
use futures::join;
use leptos::*; use leptos::*;
use leptos_router::use_query_map; use leptos_router::use_query_map;
use serde::{Deserialize, Serialize};
use url::Url;
#[derive(Default, Clone, Deserialize, Serialize)]
struct SearchResults {
articles: Vec<DbArticle>,
instance: Option<DbInstance>,
}
#[component] #[component]
pub fn Search() -> impl IntoView { pub fn Search() -> impl IntoView {
let params = use_query_map(); let params = use_query_map();
let query = params.get_untracked().get("query").cloned().unwrap(); let query = move || params.get().get("query").cloned().unwrap();
let query_ = query.clone(); let search_results = create_resource(query, move |query| async move {
let search_results = create_resource( let mut search_results = SearchResults::default();
move || query_.clone(), let api_client = GlobalState::api_client();
move |query| async move { let url = Url::parse(&query);
GlobalState::api_client() let search_data = SearchArticleData { query };
.search(&SearchArticleData { query }) let search = api_client.search(&search_data);
.await
.unwrap() // If its a valid url, also attempt to resolve as federation object
}, if let Ok(url) = url {
); let resolve_article = api_client.resolve_article(url.clone());
let resolve_instance = api_client.resolve_instance(url);
let (search, resolve_article, resolve_instance) =
join!(search, resolve_article, resolve_instance);
search_results.instance = resolve_instance.ok();
if let Ok(article) = resolve_article {
search_results.articles.push(article);
}
search_results.articles.append(&mut search.unwrap())
} else {
search_results.articles.append(&mut search.await.unwrap())
}
search_results
});
view! { view! {
<h1>"Search results for "{query}</h1> <h1>"Search results for "{query}</h1>
<Suspense fallback=|| view! { "Loading..." }> { <Suspense fallback=|| view! { "Loading..." }> {
move || search_results.get().map(|search_results| { move || search_results.get().map(|search_results| {
let is_empty = search_results.is_empty(); let is_empty = search_results.articles.is_empty() && search_results.instance.is_none();
view! { view! {
<Show when=move || !is_empty <Show when=move || !is_empty
fallback=|| view! { <p>No results found</p> }> fallback=|| view! { <p>No results found</p> }>
<ul> <ul>
{ {
search_results // render resolved instance
if let Some(instance) = &search_results.instance {
let ap_id = instance.ap_id.to_string();
vec![view! { <li>
<a href={format!("/instance/{ap_id}")}>{ap_id}</a>
</li>}]
} else { vec![] }
}
{
// render articles from resolve/search
search_results.articles
.iter() .iter()
.map(|a| view! { <li> .map(|a| view! { <li>
<a href={format!("/article/{}", a.title)}>{a.title()}</a> <a href={format!("/article/{}", a.title)}>{a.title()}</a>