From b736eba0a09ec5c702ac70840a76b50fb1ec104b Mon Sep 17 00:00:00 2001 From: Simon Bruder Date: Mon, 8 Jul 2024 22:39:54 +0200 Subject: [PATCH] Show parent hierarchy in item list and details --- src/frontend/item.rs | 24 ++++++++++++++++++++++-- src/manage/item.rs | 31 +++++++++++++++++++++++++++++++ src/schema.rs | 1 + templates/item_details.html | 9 +++++++-- templates/item_list.html | 16 +++++++++++++++- 5 files changed, 76 insertions(+), 5 deletions(-) diff --git a/src/frontend/item.rs b/src/frontend/item.rs index 4515010..5c718ad 100644 --- a/src/frontend/item.rs +++ b/src/frontend/item.rs @@ -27,6 +27,7 @@ struct ItemDetails { req: HttpRequest, item: Item, item_class: ItemClass, + parents: Vec, } #[get("/item/{id}")] @@ -45,10 +46,15 @@ async fn show_item( .await .map_err(error::ErrorInternalServerError)?; + let parents = manage::item::get_parents_details(&mut pool.get().await.unwrap(), item.id) + .await + .map_err(error::ErrorInternalServerError)?; + Ok(ItemDetails { req, item, item_class, + parents, }) } @@ -56,8 +62,12 @@ async fn show_item( #[template(path = "item_list.html")] struct ItemList { req: HttpRequest, - items: Vec, + // Both a Vec and a HashMap are used to have both the natural order, + // as well as arbitrary access capabilities. + item_list: Vec, + items: HashMap, item_classes: HashMap, + item_tree: HashMap>, } #[get("/items")] @@ -65,7 +75,11 @@ async fn list_items( req: HttpRequest, pool: web::Data, ) -> actix_web::Result { - let items = manage::item::get_all(&mut pool.get().await.unwrap()) + let item_list = manage::item::get_all(&mut pool.get().await.unwrap()) + .await + .map_err(error::ErrorInternalServerError)?; + + let items = manage::item::get_all_as_map(&mut pool.get().await.unwrap()) .await .map_err(error::ErrorInternalServerError)?; @@ -73,10 +87,16 @@ async fn list_items( .await .map_err(error::ErrorInternalServerError)?; + let item_tree = manage::item::get_all_parents(&mut pool.get().await.unwrap()) + .await + .map_err(error::ErrorInternalServerError)?; + Ok(ItemList { req, + item_list, items, item_classes, + item_tree, }) } diff --git a/src/manage/item.rs b/src/manage/item.rs index 8f439bf..d9d453e 100644 --- a/src/manage/item.rs +++ b/src/manage/item.rs @@ -5,6 +5,7 @@ use std::collections::HashMap; use diesel::prelude::*; +use diesel::sql_types; use diesel_async::pg::AsyncPgConnection; use diesel_async::RunQueryDsl; use uuid::Uuid; @@ -37,6 +38,16 @@ pub async fn get_all(conn: &mut AsyncPgConnection) -> Result, diesel:: .await } +pub async fn get_all_as_map( + conn: &mut AsyncPgConnection, +) -> Result, diesel::result::Error> { + Ok(get_all(conn) + .await? + .into_iter() + .map(|i| (i.id, i)) + .collect()) +} + pub async fn update( conn: &mut AsyncPgConnection, id: Uuid, @@ -91,3 +102,23 @@ pub async fn get_all_parents( .collect::>>() }) } + +pub async fn get_parents_details( + conn: &mut AsyncPgConnection, + id: Uuid, +) -> Result, diesel::result::Error> { + define_sql_function!(fn unnest(a: sql_types::Array) -> sql_types::Uuid); + + schema::items::table + .filter( + schema::items::id.eq_any( + schema::item_tree::table + .filter(schema::item_tree::id.eq(id)) + .select(unnest(schema::item_tree::parents)) + .into_boxed(), + ), + ) + .select(Item::as_select()) + .load(conn) + .await +} diff --git a/src/schema.rs b/src/schema.rs index 799cfa4..ab62ec5 100644 --- a/src/schema.rs +++ b/src/schema.rs @@ -39,3 +39,4 @@ diesel::table! { diesel::joinable!(items -> item_classes (class)); diesel::allow_tables_to_appear_in_same_query!(item_classes, items); +diesel::allow_tables_to_appear_in_same_query!(items, item_tree); diff --git a/templates/item_details.html b/templates/item_details.html index 368f80d..213c243 100644 --- a/templates/item_details.html +++ b/templates/item_details.html @@ -36,10 +36,15 @@ SPDX-License-Identifier: AGPL-3.0-or-later - Parent + Parents - {% if let Some(parent) = item.parent %}{{ parent }}{% else %}-{% endif %} + diff --git a/templates/item_list.html b/templates/item_list.html index d9b3d64..0792a44 100644 --- a/templates/item_list.html +++ b/templates/item_list.html @@ -15,14 +15,28 @@ SPDX-License-Identifier: AGPL-3.0-or-later Name Class + Parents - {% for item in items -%} + {% for item in item_list -%} {% let class = item_classes.get(item.class).unwrap() %} {{ item.name }} {{ class.name }} + + + {% endfor -%}