mirror of
https://github.com/perstarkse/minne.git
synced 2026-04-26 10:48:37 +02:00
feat: category filtering knowledge and content
This commit is contained in:
@@ -1,11 +1,12 @@
|
||||
use axum::{
|
||||
extract::{Path, State},
|
||||
extract::{Path, Query, State},
|
||||
response::IntoResponse,
|
||||
Form,
|
||||
};
|
||||
use axum_htmx::{HxBoosted, HxRequest};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use common::storage::types::{text_content::TextContent, user::User};
|
||||
use common::storage::types::{file_info::FileInfo, text_content::TextContent, user::User};
|
||||
|
||||
use crate::{
|
||||
html_state::HtmlState,
|
||||
@@ -19,21 +20,52 @@ use crate::{
|
||||
pub struct ContentPageData {
|
||||
user: User,
|
||||
text_contents: Vec<TextContent>,
|
||||
categories: Vec<String>,
|
||||
selected_category: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct FilterParams {
|
||||
category: Option<String>,
|
||||
}
|
||||
|
||||
pub async fn show_content_page(
|
||||
State(state): State<HtmlState>,
|
||||
RequireUser(user): RequireUser,
|
||||
Query(params): Query<FilterParams>,
|
||||
HxRequest(is_htmx): HxRequest,
|
||||
HxBoosted(is_boosted): HxBoosted,
|
||||
) -> Result<impl IntoResponse, HtmlError> {
|
||||
let text_contents = User::get_text_contents(&user.id, &state.db).await?;
|
||||
// Normalize empty strings to None
|
||||
let has_category_param = params.category.is_some();
|
||||
let category_filter = params.category.as_deref().unwrap_or("").trim();
|
||||
|
||||
Ok(TemplateResponse::new_template(
|
||||
"content/base.html",
|
||||
ContentPageData {
|
||||
user,
|
||||
text_contents,
|
||||
},
|
||||
))
|
||||
// load categories and filtered/all contents
|
||||
let categories = User::get_user_categories(&user.id, &state.db).await?;
|
||||
let text_contents = if !category_filter.is_empty() {
|
||||
User::get_text_contents_by_category(&user.id, category_filter, &state.db).await?
|
||||
} else {
|
||||
User::get_text_contents(&user.id, &state.db).await?
|
||||
};
|
||||
|
||||
let data = ContentPageData {
|
||||
user,
|
||||
text_contents,
|
||||
categories,
|
||||
selected_category: params.category.clone(),
|
||||
};
|
||||
|
||||
if is_htmx && !is_boosted && has_category_param {
|
||||
// If HTMX partial request with filter applied, return partial content list update
|
||||
return Ok(TemplateResponse::new_partial(
|
||||
"content/base.html",
|
||||
"main",
|
||||
data,
|
||||
));
|
||||
}
|
||||
|
||||
// Otherwise full page response including layout
|
||||
Ok(TemplateResponse::new_template("content/base.html", data))
|
||||
}
|
||||
|
||||
pub async fn show_text_content_edit_form(
|
||||
@@ -79,12 +111,47 @@ pub async fn patch_text_content(
|
||||
.await?;
|
||||
|
||||
let text_contents = User::get_text_contents(&user.id, &state.db).await?;
|
||||
let categories = User::get_user_categories(&user.id, &state.db).await?;
|
||||
|
||||
Ok(TemplateResponse::new_partial(
|
||||
"content/base.html",
|
||||
"main",
|
||||
ContentPageData {
|
||||
user,
|
||||
text_contents,
|
||||
categories,
|
||||
selected_category: None,
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
pub async fn delete_text_content(
|
||||
State(state): State<HtmlState>,
|
||||
RequireUser(user): RequireUser,
|
||||
Path(id): Path<String>,
|
||||
) -> Result<impl IntoResponse, HtmlError> {
|
||||
// Get and validate the text content
|
||||
let text_content = User::get_and_validate_text_content(&id, &user.id, &state.db).await?;
|
||||
|
||||
// If it has file info, delete that too
|
||||
if let Some(file_info) = &text_content.file_info {
|
||||
FileInfo::delete_by_id(&file_info.id, &state.db).await?;
|
||||
}
|
||||
|
||||
// Delete the text content
|
||||
state.db.delete_item::<TextContent>(&id).await?;
|
||||
|
||||
// Get updated content, categories and return the refreshed list
|
||||
let text_contents = User::get_text_contents(&user.id, &state.db).await?;
|
||||
let categories = User::get_user_categories(&user.id, &state.db).await?;
|
||||
|
||||
Ok(TemplateResponse::new_template(
|
||||
"content/content_list.html",
|
||||
ContentPageData {
|
||||
user,
|
||||
text_contents,
|
||||
categories,
|
||||
selected_category: None,
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
mod handlers;
|
||||
|
||||
use axum::{extract::FromRef, routing::get, Router};
|
||||
use handlers::{patch_text_content, show_content_page, show_text_content_edit_form};
|
||||
use handlers::{
|
||||
delete_text_content, patch_text_content, show_content_page, show_text_content_edit_form,
|
||||
};
|
||||
|
||||
use crate::html_state::HtmlState;
|
||||
|
||||
@@ -14,6 +16,8 @@ where
|
||||
.route("/content", get(show_content_page))
|
||||
.route(
|
||||
"/content/:id",
|
||||
get(show_text_content_edit_form).patch(patch_text_content),
|
||||
get(show_text_content_edit_form)
|
||||
.patch(patch_text_content)
|
||||
.delete(delete_text_content),
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user