This commit is contained in:
2023-05-11 16:51:57 +02:00
parent 20b1a94dc8
commit 38fc0d2f83
3 changed files with 81 additions and 50 deletions

View File

@@ -2,7 +2,7 @@ use maud::{html, Markup};
use crate::models::*;
use crate::ClientState;
use uuid::uuid;
use uuid::{uuid, Uuid};
pub struct Inventory {
doc: Markup,
@@ -19,7 +19,7 @@ impl Inventory {
div ."col-span-2" {
h1 ."text-2xl" ."mb-5" ."text-center" { "Items" }
@if state.active_category_id.is_some() {
({<InventoryItemList as Into<Markup>>::into(InventoryItemList::build(categories.iter().find(|category| category.active).unwrap().items()))})
({<InventoryItemList as Into<Markup>>::into(InventoryItemList::build(categories.iter().find(|category| category.active).unwrap().items(), state.edit_item))})
}
({<InventoryNewItemForm as Into<Markup>>::into(InventoryNewItemForm::build(&state, &categories))})
@@ -155,7 +155,7 @@ pub struct InventoryItemList {
}
impl InventoryItemList {
pub fn build(items: &Vec<Item>) -> Self {
pub fn build(items: &Vec<Item>, edit_item: Option<Uuid>) -> Self {
let biggest_item_weight: u32 = items.iter().map(|item| item.weight).max().unwrap_or(1);
let doc = html!(
div #items {
@@ -178,41 +178,59 @@ impl InventoryItemList {
}
tbody {
@for item in items {
tr ."h-10" ."even:bg-gray-100" ."hover:bg-purple-100" {
td ."border" ."p-0" {
a
."p-2" ."w-full" ."inline-block"
href=(
format!("/inventory/item/{id}/", id=item.id)
) {
(item.name.clone())
}
}
td ."border" ."p-2" style="position:relative;" {
p { (item.weight.to_string()) }
div ."bg-blue-600" ."h-1.5" style=(format!("
width: {width}%;
position:absolute;
left:0;
bottom:0;
right:0;", width=(f64::from(item.weight) / f64::from(biggest_item_weight) * 100.0))) {}
}
td
."border"
."bg-red-200"
."hover:bg-red-400"
."cursor-pointer"
."w-8"
."text-center"
{
@if edit_item.map_or(false, |edit_item| edit_item == item.id) {
tr { td { (item.name.clone()) " is being edited" }}
} @else {
tr ."h-10" ."even:bg-gray-100" ."hover:bg-purple-100" {
td ."border" ."p-0" {
a
href = (format!("/inventory/item/{id}/delete", id = item.id))
{
button {
span ."mdi" ."mdi-delete" ."text-xl" {}
."p-2" ."w-full" ."inline-block"
href=(
format!("/inventory/item/{id}/", id=item.id)
) {
(item.name.clone())
}
}
}
td ."border" ."p-2" style="position:relative;" {
p { (item.weight.to_string()) }
div ."bg-blue-600" ."h-1.5" style=(format!("
width: {width}%;
position:absolute;
left:0;
bottom:0;
right:0;", width=(f64::from(item.weight) / f64::from(biggest_item_weight) * 100.0))) {}
}
td
."border"
."bg-blue-200"
."hover:bg-blue-400"
."cursor-pointer"
."w-8"
."text-center"
{
a href = (format!("?edit_item={id}", id = item.id))
{
button {
span ."mdi" ."mdi-pencil" ."text-xl" {}
}
}
}
td
."border"
."bg-red-200"
."hover:bg-red-400"
."cursor-pointer"
."w-8"
."text-center"
{
a href = (format!("/inventory/item/{id}/delete", id = item.id))
{
button {
span ."mdi" ."mdi-delete" ."text-xl" {}
}
}
}
}
}
}

View File

@@ -1,7 +1,6 @@
#![allow(unused_imports)]
use axum::{
extract::Path,
extract::State,
extract::{Path, Query, State},
headers,
headers::Header,
http::{header::HeaderMap, StatusCode},
@@ -39,12 +38,14 @@ pub struct AppState {
#[derive(Clone)]
pub struct ClientState {
pub active_category_id: Option<Uuid>,
pub edit_item: Option<Uuid>,
}
impl ClientState {
pub fn new() -> Self {
ClientState {
active_category_id: None,
edit_item: None,
}
}
}
@@ -65,7 +66,7 @@ async fn main() -> Result<(), sqlx::Error> {
.max_connections(5)
.connect_with(
SqliteConnectOptions::new()
.filename("/home/hannes-private/sync/items/items.sqlite")
.filename(std::env::var("SQLITE_DATABASE").expect("env SQLITE_DATABASE not found"))
.pragma("foreign_keys", "1"),
)
.await
@@ -107,16 +108,31 @@ async fn root() -> (StatusCode, Html<String>) {
)
}
#[derive(Deserialize)]
struct InventoryQuery {
edit_item: Option<Uuid>,
}
impl Default for InventoryQuery {
fn default() -> Self {
Self { edit_item: None }
}
}
async fn inventory_active(
Path(id): Path<String>,
State(state): State<AppState>,
State(mut state): State<AppState>,
Query(inventory_query): Query<InventoryQuery>,
) -> Result<(StatusCode, Html<String>), (StatusCode, Html<String>)> {
state.client_state.edit_item = inventory_query.edit_item;
inventory(state, Some(id)).await
}
async fn inventory_inactive(
State(state): State<AppState>,
State(mut state): State<AppState>,
Query(inventory_query): Query<InventoryQuery>,
) -> Result<(StatusCode, Html<String>), (StatusCode, Html<String>)> {
state.client_state.edit_item = inventory_query.edit_item;
inventory(state, None).await
}
@@ -147,7 +163,7 @@ async fn inventory(
for category in &mut categories {
category
.populate_items()
.populate_items(&state.database_pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, Html::from(e.to_string())))?;

View File

@@ -114,13 +114,10 @@ impl<'a> Category {
self.items().iter().map(|item| item.weight).sum()
}
pub async fn populate_items(&'a mut self) -> Result<(), Error> {
let pool = SqlitePoolOptions::new()
.max_connections(5)
.connect("sqlite:///home/hannes-private/sync/items/items.sqlite")
.await
.unwrap();
pub async fn populate_items(
&'a mut self,
pool: &sqlx::Pool<sqlx::Sqlite>,
) -> Result<(), Error> {
let items = sqlx::query(&format!(
"SELECT
id,name,weight,description,category_id
@@ -128,7 +125,7 @@ impl<'a> Category {
WHERE category_id = '{id}'",
id = self.id
))
.fetch(&pool)
.fetch(pool)
.map_ok(std::convert::TryInto::try_into)
.try_collect::<Vec<Result<Item, Error>>>()
.await?