li7y/src/frontend/item_class.rs

260 lines
8.1 KiB
Rust
Raw Normal View History

2024-07-07 13:48:31 +02:00
// SPDX-FileCopyrightText: 2024 Simon Bruder <simon@sbruder.de>
//
// SPDX-License-Identifier: AGPL-3.0-or-later
2024-07-11 01:12:34 +02:00
use actix_web::{error, get, post, web, Responder};
use maud::html;
use sqlx::PgPool;
2024-07-07 13:48:31 +02:00
use uuid::Uuid;
2024-07-11 01:12:34 +02:00
use super::templates::{self, forms, TemplateConfig};
2024-07-07 13:48:31 +02:00
use crate::manage;
use crate::models::*;
pub fn config(cfg: &mut web::ServiceConfig) {
cfg.service(show_item_class)
.service(list_item_classes)
.service(add_item_class)
.service(add_item_class_post)
.service(edit_item_class)
.service(edit_item_class_post);
}
#[get("/item-class/{id}")]
async fn show_item_class(
pool: web::Data<PgPool>,
2024-07-07 13:48:31 +02:00
path: web::Path<Uuid>,
) -> actix_web::Result<impl Responder> {
let id = path.into_inner();
let item_class = manage::item_class::get(&pool, id)
.await
2024-07-07 13:48:31 +02:00
.map_err(error::ErrorInternalServerError)?;
// TODO: Once async closures are stable, use map_or on item_class.parent instead
let parent = match item_class.parent {
Some(id) => manage::item_class::get(&pool, id)
.await
.map(Some)
.map_err(error::ErrorInternalServerError)?,
None => None,
};
2024-07-07 13:48:31 +02:00
let children = manage::item_class::children(&pool, id)
2024-07-11 13:50:59 +02:00
.await
.map_err(error::ErrorInternalServerError)?;
2024-07-11 01:12:34 +02:00
let mut title = item_class.name.clone();
title.push_str(" Item Details");
2024-07-07 13:48:31 +02:00
2024-07-11 01:12:34 +02:00
Ok(templates::base(
TemplateConfig {
path: &format!("/item-class/{}", item_class.id),
title: Some(&title),
page_title: Some(Box::new(item_class.name.clone())),
page_actions: vec![
(templates::helpers::PageAction {
href: &format!("/item-class/{}/edit", item_class.id),
name: "Edit",
}),
],
..Default::default()
},
html! {
table .table {
tr {
th { "UUID" }
td { (item_class.id) }
}
tr {
th { "Name" }
td { (item_class.name) }
}
@if let Some(parent) = parent {
tr {
th { "Parent" }
td { a href={ "/item-class/" (parent.id) } { (parent.name) } }
}
}
}
2024-07-11 13:50:59 +02:00
@if !children.is_empty() {
h3 .mt-4 { "Children" }
ul {
@for child in children {
li {
a href={ "/item-class/" (child.id) } { (child.name) }
}
}
}
}
2024-07-11 01:12:34 +02:00
},
))
2024-07-07 13:48:31 +02:00
}
#[get("/item-classes")]
async fn list_item_classes(pool: web::Data<PgPool>) -> actix_web::Result<impl Responder> {
let item_classes_ids = sqlx::query_scalar!("SELECT id FROM item_classes ORDER BY created_at")
.fetch_all(pool.as_ref())
.await
.map_err(error::ErrorInternalServerError)?;
let item_classes = manage::item_class::get_all_as_map(&pool)
.await
2024-07-07 13:48:31 +02:00
.map_err(error::ErrorInternalServerError)?;
2024-07-11 01:12:34 +02:00
Ok(templates::base(
TemplateConfig {
path: "/item-classes",
title: Some("Item Class List"),
page_title: Some(Box::new("Item Class List")),
page_actions: vec![
(templates::helpers::PageAction {
href: "/item-classes/add",
name: "Add",
}),
],
..Default::default()
},
html! {
table .table {
thead {
tr {
th { "Name" }
th { "Parents" }
}
}
tbody {
@for item_class in item_classes_ids {
@let item_class = item_classes.get(&item_class).unwrap();
2024-07-11 01:12:34 +02:00
tr {
td { a href={ "/item-class/" (item_class.id) } { (item_class.name) } }
td {
@if let Some(parent) = item_class.parent {
@let parent = item_classes.get(&parent).unwrap();
a href={ "/item-class/" (parent.id) } { (parent.name) }
} @else {
"-"
}
}
}
}
}
}
},
))
2024-07-07 13:48:31 +02:00
}
#[get("/item-classes/add")]
2024-07-11 01:12:34 +02:00
async fn add_item_class() -> actix_web::Result<impl Responder> {
Ok(templates::base(
TemplateConfig {
path: "/items-classes/add",
title: Some("Add Item Class"),
page_title: Some(Box::new("Add Item Class")),
..Default::default()
},
html! {
form method="POST" {
(forms::InputGroup {
r#type: forms::InputType::Text,
name: "name",
title: "Name",
required: true,
..Default::default()
})
(forms::InputGroup {
r#type: forms::InputType::Text,
name: "parent",
title: "Parent",
disabled: true,
..Default::default()
})
2024-07-11 01:12:34 +02:00
button .btn.btn-primary type="submit" { "Add" }
}
},
))
2024-07-07 13:48:31 +02:00
}
#[post("/item-classes/add")]
async fn add_item_class_post(
data: web::Form<NewItemClass>,
pool: web::Data<PgPool>,
2024-07-07 13:48:31 +02:00
) -> actix_web::Result<impl Responder> {
let item = manage::item_class::add(&pool, data.into_inner())
.await
.map_err(error::ErrorInternalServerError)?;
2024-07-07 13:48:31 +02:00
Ok(web::Redirect::to("/item-class/".to_owned() + &item.id.to_string()).see_other())
}
#[get("/item-class/{id}/edit")]
async fn edit_item_class(
pool: web::Data<PgPool>,
2024-07-07 13:48:31 +02:00
path: web::Path<Uuid>,
) -> actix_web::Result<impl Responder> {
let id = path.into_inner();
let item_class = manage::item_class::get(&pool, id)
.await
2024-07-07 13:48:31 +02:00
.map_err(error::ErrorInternalServerError)?;
2024-07-11 01:12:34 +02:00
let mut title = item_class.name.clone();
title.push_str(" Item Details");
Ok(templates::base(
TemplateConfig {
path: &format!("/items-class/{}/add", id),
title: Some(&title),
page_title: Some(Box::new(item_class.name.clone())),
..Default::default()
},
html! {
form method="POST" {
(forms::InputGroup {
r#type: forms::InputType::Text,
name: "id",
title: "UUID",
disabled: true,
required: true,
value: Some(item_class.id.to_string().as_str()),
})
(forms::InputGroup {
r#type: forms::InputType::Text,
name: "name",
title: "Name",
required: true,
value: Some(&item_class.name),
..Default::default()
})
(forms::InputGroup {
r#type: forms::InputType::Text,
name: "parent",
title: "Parent",
disabled: item_class.parent.is_none(),
value: item_class.parent.map(|id| id.to_string()).as_deref(),
..Default::default()
})
2024-07-11 01:12:34 +02:00
button .btn.btn-primary type="submit" { "Edit" }
}
},
))
2024-07-07 13:48:31 +02:00
}
#[post("/item-class/{id}/edit")]
async fn edit_item_class_post(
pool: web::Data<PgPool>,
2024-07-07 13:48:31 +02:00
path: web::Path<Uuid>,
data: web::Form<NewItemClass>,
) -> actix_web::Result<impl Responder> {
let id = path.into_inner();
let item_class = manage::item_class::update(&pool, id, data.into_inner())
.await
.map_err(error::ErrorInternalServerError)?;
2024-07-07 13:48:31 +02:00
Ok(web::Redirect::to("/item-class/".to_owned() + &item_class.id.to_string()).see_other())
}