From 09dfac9104d23d4f4fb8618a5cbbc23c030f571c Mon Sep 17 00:00:00 2001 From: Simon Bruder Date: Fri, 12 Jul 2024 17:23:17 +0200 Subject: [PATCH] Add quick jump feature --- ...338a7275ba56a9b17278fd886175c3a27b0dd.json | 22 ++++++++ ...86f1f9fdb076e8f8b98f10fc1b981cfe8038c.json | 52 +++++++++++++++++++ src/frontend/mod.rs | 49 ++++++++++++++++- src/frontend/templates/mod.rs | 6 ++- src/manage/item.rs | 6 +++ src/manage/mod.rs | 23 ++++++++ src/models.rs | 6 +++ 7 files changed, 162 insertions(+), 2 deletions(-) create mode 100644 .sqlx/query-6dd8b63f4aaefbc1ab5d5a9bae2338a7275ba56a9b17278fd886175c3a27b0dd.json create mode 100644 .sqlx/query-7eeb752c8b00ac4000104f0254186f1f9fdb076e8f8b98f10fc1b981cfe8038c.json diff --git a/.sqlx/query-6dd8b63f4aaefbc1ab5d5a9bae2338a7275ba56a9b17278fd886175c3a27b0dd.json b/.sqlx/query-6dd8b63f4aaefbc1ab5d5a9bae2338a7275ba56a9b17278fd886175c3a27b0dd.json new file mode 100644 index 0000000..bef38c8 --- /dev/null +++ b/.sqlx/query-6dd8b63f4aaefbc1ab5d5a9bae2338a7275ba56a9b17278fd886175c3a27b0dd.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT type as \"type!\" FROM\n (SELECT id, 'item' AS \"type\" FROM items\n UNION ALL\n SELECT id, 'item_class' AS \"type\" FROM item_classes) id_mapping\n WHERE id = $1", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "type!", + "type_info": "Text" + } + ], + "parameters": { + "Left": [ + "Uuid" + ] + }, + "nullable": [ + null + ] + }, + "hash": "6dd8b63f4aaefbc1ab5d5a9bae2338a7275ba56a9b17278fd886175c3a27b0dd" +} diff --git a/.sqlx/query-7eeb752c8b00ac4000104f0254186f1f9fdb076e8f8b98f10fc1b981cfe8038c.json b/.sqlx/query-7eeb752c8b00ac4000104f0254186f1f9fdb076e8f8b98f10fc1b981cfe8038c.json new file mode 100644 index 0000000..9465980 --- /dev/null +++ b/.sqlx/query-7eeb752c8b00ac4000104f0254186f1f9fdb076e8f8b98f10fc1b981cfe8038c.json @@ -0,0 +1,52 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT * FROM items WHERE short_id = $1", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Uuid" + }, + { + "ordinal": 1, + "name": "name", + "type_info": "Varchar" + }, + { + "ordinal": 2, + "name": "parent", + "type_info": "Uuid" + }, + { + "ordinal": 3, + "name": "class", + "type_info": "Uuid" + }, + { + "ordinal": 4, + "name": "created_at", + "type_info": "Timestamptz" + }, + { + "ordinal": 5, + "name": "short_id", + "type_info": "Int4" + } + ], + "parameters": { + "Left": [ + "Int4" + ] + }, + "nullable": [ + false, + true, + true, + false, + false, + false + ] + }, + "hash": "7eeb752c8b00ac4000104f0254186f1f9fdb076e8f8b98f10fc1b981cfe8038c" +} diff --git a/src/frontend/mod.rs b/src/frontend/mod.rs index 88e78fc..fa85a71 100644 --- a/src/frontend/mod.rs +++ b/src/frontend/mod.rs @@ -6,11 +6,18 @@ mod item; mod item_class; mod templates; -use actix_web::{get, web, Responder}; +use actix_web::{error, get, web, Responder}; use maud::html; +use serde::Deserialize; +use sqlx::PgPool; +use uuid::Uuid; + +use crate::manage; +use crate::models::EntityType; pub fn config(cfg: &mut web::ServiceConfig) { cfg.service(index) + .service(jump) .configure(item::config) .configure(item_class::config); } @@ -19,3 +26,43 @@ pub fn config(cfg: &mut web::ServiceConfig) { async fn index() -> impl Responder { templates::base(templates::TemplateConfig::default(), html! {}) } + +#[derive(Deserialize)] +struct JumpData { + id: String, +} + +#[get("/jump")] +async fn jump( + pool: web::Data, + data: web::Query, +) -> Result { + let mut id = data.id.clone(); + + let entity_type = if let Ok(id) = Uuid::parse_str(&id) { + manage::query_entity_type(&pool, id) + .await + .map_err(error::ErrorInternalServerError)? + } else if let Ok(short_id) = id.parse::() { + if let Ok(item) = manage::item::get_by_short_id(&pool, short_id) + .await + .map_err(error::ErrorInternalServerError) + { + id = item.id.to_string(); + Some(EntityType::Item) + } else { + None + } + } else { + None + }; + + if let Some(prefix) = entity_type.map(|entity_type| match entity_type { + EntityType::Item => "item", + EntityType::ItemClass => "item-class", + }) { + Ok(web::Redirect::to(format!("/{prefix}/{id}")).see_other()) + } else { + Ok(web::Redirect::to(format!("/items/add?name={id}")).see_other()) + } +} diff --git a/src/frontend/templates/mod.rs b/src/frontend/templates/mod.rs index 9b8f5f7..f866468 100644 --- a/src/frontend/templates/mod.rs +++ b/src/frontend/templates/mod.rs @@ -30,11 +30,15 @@ fn navbar(path: &str) -> Markup { } div .collapse.navbar-collapse #navbar-expander { - ul .navbar-nav.me-auto.mb-2.mb-md-0 { + ul .navbar-nav.me-md-3.mb-2.mb-md-0 { @for (target, name) in NAVBAR_ITEMS { li .nav-item { a .nav-link .active[path == *target] href=(target) { (name) } } } } + + form .d-flex.flex-fill role="search" action="/jump" { + input .form-control.me-2 type="search" name="id" placeholder="Jump to ID"; + } } } } diff --git a/src/manage/item.rs b/src/manage/item.rs index 1a33f01..f24d547 100644 --- a/src/manage/item.rs +++ b/src/manage/item.rs @@ -27,6 +27,12 @@ pub async fn get(pool: &PgPool, id: Uuid) -> Result { .await } +pub async fn get_by_short_id(pool: &PgPool, short_id: i32) -> Result { + query_as!(Item, "SELECT * FROM items WHERE short_id = $1", short_id) + .fetch_one(pool) + .await +} + pub async fn get_all(pool: &PgPool) -> Result, sqlx::Error> { query_as!(Item, "SELECT * FROM items ORDER BY created_at") .fetch_all(pool) diff --git a/src/manage/mod.rs b/src/manage/mod.rs index e5adb01..35c0b31 100644 --- a/src/manage/mod.rs +++ b/src/manage/mod.rs @@ -4,3 +4,26 @@ pub mod item; pub mod item_class; + +use sqlx::{query, PgPool}; +use uuid::Uuid; + +use crate::models::EntityType; + +pub async fn query_entity_type(pool: &PgPool, id: Uuid) -> Result, sqlx::Error> { + Ok(query!( + r#"SELECT type as "type!" FROM + (SELECT id, 'item' AS "type" FROM items + UNION ALL + SELECT id, 'item_class' AS "type" FROM item_classes) id_mapping + WHERE id = $1"#, + id + ) + .fetch_optional(pool) + .await? + .map(|row| match row.r#type.as_str() { + "item" => EntityType::Item, + "item_class" => EntityType::ItemClass, + _ => unreachable!("database returned impossible type"), + })) +} diff --git a/src/models.rs b/src/models.rs index b743a9c..f4d5d6e 100644 --- a/src/models.rs +++ b/src/models.rs @@ -6,6 +6,12 @@ use serde::{Deserialize, Serialize}; use time::OffsetDateTime; use uuid::Uuid; +#[derive(Deserialize)] +pub enum EntityType { + Item, + ItemClass, +} + #[derive(Clone, Debug, Serialize, sqlx::FromRow)] pub struct Item { pub id: Uuid,