mirror of
https://github.com/perstarkse/minne.git
synced 2026-03-27 20:01:31 +01:00
design: neobrutalist_theme into main
This commit is contained in:
@@ -35,5 +35,6 @@ where
|
||||
.add_protected_routes(routes::content::router())
|
||||
.add_protected_routes(routes::knowledge::router())
|
||||
.add_protected_routes(routes::ingestion::router())
|
||||
.with_compression()
|
||||
.build()
|
||||
}
|
||||
|
||||
7
html-router/src/middlewares/compression.rs
Normal file
7
html-router/src/middlewares/compression.rs
Normal file
@@ -0,0 +1,7 @@
|
||||
use tower_http::compression::CompressionLayer;
|
||||
|
||||
/// Provides a default compression layer that negotiates encoding based on the
|
||||
/// `Accept-Encoding` header of the incoming request.
|
||||
pub fn compression_layer() -> CompressionLayer {
|
||||
CompressionLayer::new()
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
pub mod analytics_middleware;
|
||||
pub mod auth_middleware;
|
||||
pub mod compression;
|
||||
pub mod response_middleware;
|
||||
|
||||
@@ -13,7 +13,7 @@ use crate::{
|
||||
html_state::HtmlState,
|
||||
middlewares::{
|
||||
analytics_middleware::analytics_middleware, auth_middleware::require_auth,
|
||||
response_middleware::with_template_response,
|
||||
compression::compression_layer, response_middleware::with_template_response,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -48,6 +48,7 @@ pub struct RouterFactory<S> {
|
||||
nested_protected_routes: Vec<(String, Router<S>)>,
|
||||
custom_middleware: MiddleWareVecType<S>,
|
||||
public_assets_config: Option<AssetsConfig>,
|
||||
compression_enabled: bool,
|
||||
}
|
||||
|
||||
struct AssetsConfig {
|
||||
@@ -69,6 +70,7 @@ where
|
||||
nested_protected_routes: Vec::new(),
|
||||
custom_middleware: Vec::new(),
|
||||
public_assets_config: None,
|
||||
compression_enabled: false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,6 +117,12 @@ where
|
||||
self
|
||||
}
|
||||
|
||||
/// Enables response compression when building the router.
|
||||
pub fn with_compression(mut self) -> Self {
|
||||
self.compression_enabled = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build(self) -> Router<S> {
|
||||
// Start with an empty router
|
||||
let mut public_router = Router::new();
|
||||
@@ -169,21 +177,26 @@ where
|
||||
}
|
||||
|
||||
// Apply common middleware
|
||||
router = router.layer(from_fn_with_state(
|
||||
self.app_state.clone(),
|
||||
analytics_middleware::<HtmlState>,
|
||||
));
|
||||
router = router.layer(map_response_with_state(
|
||||
self.app_state.clone(),
|
||||
with_template_response::<HtmlState>,
|
||||
));
|
||||
router = router.layer(
|
||||
AuthSessionLayer::<User, String, SessionSurrealPool<Any>, Surreal<Any>>::new(Some(
|
||||
self.app_state.db.client.clone(),
|
||||
))
|
||||
.with_config(AuthConfig::<String>::default()),
|
||||
);
|
||||
router = router.layer(SessionLayer::new((*self.app_state.session_store).clone()));
|
||||
|
||||
if self.compression_enabled {
|
||||
router = router.layer(compression_layer());
|
||||
}
|
||||
|
||||
router
|
||||
.layer(from_fn_with_state(
|
||||
self.app_state.clone(),
|
||||
analytics_middleware::<HtmlState>,
|
||||
))
|
||||
.layer(map_response_with_state(
|
||||
self.app_state.clone(),
|
||||
with_template_response::<HtmlState>,
|
||||
))
|
||||
.layer(
|
||||
AuthSessionLayer::<User, String, SessionSurrealPool<Any>, Surreal<Any>>::new(Some(
|
||||
self.app_state.db.client.clone(),
|
||||
))
|
||||
.with_config(AuthConfig::<String>::default()),
|
||||
)
|
||||
.layer(SessionLayer::new((*self.app_state.session_store).clone()))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -406,4 +406,4 @@ pub async fn patch_image_prompt(
|
||||
settings: new_settings,
|
||||
},
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,11 +3,12 @@ use axum::{
|
||||
response::IntoResponse,
|
||||
Form,
|
||||
};
|
||||
use axum_htmx::{HxBoosted, HxRequest};
|
||||
use axum_htmx::{HxBoosted, HxRequest, HxTarget};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use common::storage::types::{
|
||||
conversation::Conversation, file_info::FileInfo, text_content::TextContent, user::User, knowledge_entity::KnowledgeEntity, text_chunk::TextChunk,
|
||||
conversation::Conversation, file_info::FileInfo, knowledge_entity::KnowledgeEntity,
|
||||
text_chunk::TextChunk, text_content::TextContent, user::User,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
@@ -27,6 +28,12 @@ pub struct ContentPageData {
|
||||
conversation_archive: Vec<Conversation>,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct RecentTextContentData {
|
||||
pub user: User,
|
||||
pub text_contents: Vec<TextContent>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct FilterParams {
|
||||
category: Option<String>,
|
||||
@@ -102,12 +109,25 @@ pub async fn patch_text_content(
|
||||
State(state): State<HtmlState>,
|
||||
RequireUser(user): RequireUser,
|
||||
Path(id): Path<String>,
|
||||
HxTarget(target): HxTarget,
|
||||
Form(form): Form<PatchTextContentParams>,
|
||||
) -> Result<impl IntoResponse, HtmlError> {
|
||||
User::get_and_validate_text_content(&id, &user.id, &state.db).await?;
|
||||
|
||||
TextContent::patch(&id, &form.context, &form.category, &form.text, &state.db).await?;
|
||||
|
||||
if target.as_deref() == Some("latest_content_section") {
|
||||
let text_contents = User::get_latest_text_contents(&user.id, &state.db).await?;
|
||||
|
||||
return Ok(TemplateResponse::new_template(
|
||||
"dashboard/recent_content.html",
|
||||
RecentTextContentData {
|
||||
user,
|
||||
text_contents,
|
||||
},
|
||||
));
|
||||
}
|
||||
|
||||
let text_contents = User::get_text_contents(&user.id, &state.db).await?;
|
||||
let categories = User::get_user_categories(&user.id, &state.db).await?;
|
||||
let conversation_archive = User::get_user_conversations(&user.id, &state.db).await?;
|
||||
@@ -187,12 +207,6 @@ pub async fn show_recent_content(
|
||||
) -> Result<impl IntoResponse, HtmlError> {
|
||||
let text_contents = User::get_latest_text_contents(&user.id, &state.db).await?;
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct RecentTextContentData {
|
||||
pub user: User,
|
||||
pub text_contents: Vec<TextContent>,
|
||||
}
|
||||
|
||||
Ok(TemplateResponse::new_template(
|
||||
"dashboard/recent_content.html",
|
||||
RecentTextContentData {
|
||||
|
||||
@@ -4,6 +4,7 @@ use axum::{
|
||||
http::{header, HeaderMap, HeaderValue, StatusCode},
|
||||
response::IntoResponse,
|
||||
};
|
||||
use futures::try_join;
|
||||
use serde::Serialize;
|
||||
use tokio::join;
|
||||
|
||||
@@ -14,6 +15,8 @@ use crate::{
|
||||
},
|
||||
AuthSessionType,
|
||||
};
|
||||
use common::storage::store;
|
||||
use common::storage::types::user::DashboardStats;
|
||||
use common::{
|
||||
error::AppError,
|
||||
storage::types::{
|
||||
@@ -22,7 +25,6 @@ use common::{
|
||||
text_chunk::TextChunk, text_content::TextContent, user::User,
|
||||
},
|
||||
};
|
||||
use common::storage::store;
|
||||
|
||||
use crate::html_state::HtmlState;
|
||||
|
||||
@@ -30,6 +32,7 @@ use crate::html_state::HtmlState;
|
||||
pub struct IndexPageData {
|
||||
user: Option<User>,
|
||||
text_contents: Vec<TextContent>,
|
||||
stats: DashboardStats,
|
||||
active_jobs: Vec<IngestionTask>,
|
||||
conversation_archive: Vec<Conversation>,
|
||||
}
|
||||
@@ -42,19 +45,21 @@ pub async fn index_handler(
|
||||
return Ok(TemplateResponse::redirect("/signin"));
|
||||
};
|
||||
|
||||
let active_jobs = User::get_unfinished_ingestion_tasks(&user.id, &state.db).await?;
|
||||
|
||||
let text_contents = User::get_latest_text_contents(&user.id, &state.db).await?;
|
||||
|
||||
let conversation_archive = User::get_user_conversations(&user.id, &state.db).await?;
|
||||
let (text_contents, conversation_archive, stats, active_jobs) = try_join!(
|
||||
User::get_latest_text_contents(&user.id, &state.db),
|
||||
User::get_user_conversations(&user.id, &state.db),
|
||||
User::get_dashboard_stats(&user.id, &state.db),
|
||||
User::get_unfinished_ingestion_tasks(&user.id, &state.db)
|
||||
)?;
|
||||
|
||||
Ok(TemplateResponse::new_template(
|
||||
"dashboard/base.html",
|
||||
IndexPageData {
|
||||
user: Some(user),
|
||||
text_contents,
|
||||
active_jobs,
|
||||
stats,
|
||||
conversation_archive,
|
||||
active_jobs,
|
||||
},
|
||||
))
|
||||
}
|
||||
@@ -153,9 +158,8 @@ pub async fn show_active_jobs(
|
||||
) -> Result<impl IntoResponse, HtmlError> {
|
||||
let active_jobs = User::get_unfinished_ingestion_tasks(&user.id, &state.db).await?;
|
||||
|
||||
Ok(TemplateResponse::new_partial(
|
||||
Ok(TemplateResponse::new_template(
|
||||
"dashboard/active_jobs.html",
|
||||
"active_jobs_section",
|
||||
ActiveJobsData {
|
||||
user: user.clone(),
|
||||
active_jobs,
|
||||
|
||||
@@ -5,6 +5,7 @@ use axum::{
|
||||
response::IntoResponse,
|
||||
};
|
||||
use common::storage::types::{
|
||||
conversation::Conversation,
|
||||
text_content::{TextContent, TextContentSearchResult},
|
||||
user::User,
|
||||
};
|
||||
@@ -47,7 +48,9 @@ pub async fn search_result_handler(
|
||||
search_result: Vec<TextContentSearchResult>,
|
||||
query_param: String,
|
||||
user: User,
|
||||
conversation_archive: Vec<Conversation>,
|
||||
}
|
||||
let conversation_archive = User::get_user_conversations(&user.id, &state.db).await?;
|
||||
|
||||
let (search_results_for_template, final_query_param_for_template) =
|
||||
if let Some(actual_query) = params.query {
|
||||
@@ -72,6 +75,7 @@ pub async fn search_result_handler(
|
||||
search_result: search_results_for_template,
|
||||
query_param: final_query_param_for_template,
|
||||
user,
|
||||
conversation_archive,
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user