feat(secrets-mcp): 条目页按 folder/type 筛选并发版 0.3.5

- entries 路由支持 ?folder=&type= 查询,与搜索层 SearchParams 对齐
- 条目列表页增加筛选表单与说明文案
- 版本 0.3.4 → 0.3.5,同步 Cargo.lock

Made-with: Cursor
This commit is contained in:
2026-04-02 14:37:36 +08:00
parent 87a29af82d
commit 7909f7102d
4 changed files with 70 additions and 5 deletions

View File

@@ -88,6 +88,8 @@ struct EntriesPageTemplate {
total_count: i64,
shown_count: usize,
limit: u32,
filter_folder: String,
filter_type: String,
version: &'static str,
}
@@ -106,6 +108,14 @@ struct EntryListItemView {
/// Cap for HTML list (avoids loading unbounded rows into memory).
const ENTRIES_PAGE_LIMIT: u32 = 5_000;
#[derive(Deserialize)]
struct EntriesQuery {
folder: Option<String>,
/// URL query key is `type` (maps to DB column `entries.type`).
#[serde(rename = "type")]
entry_type: Option<String>,
}
// ── App state helpers ─────────────────────────────────────────────────────────
fn google_cfg(state: &AppState) -> Option<&OAuthConfig> {
@@ -510,6 +520,7 @@ async fn dashboard(
async fn entries_page(
State(state): State<AppState>,
session: Session,
Query(q): Query<EntriesQuery>,
) -> Result<Response, StatusCode> {
let Some(user_id) = current_user_id(&session).await else {
return Ok(Redirect::to("/login").into_response());
@@ -523,9 +534,22 @@ async fn entries_page(
None => return Ok(Redirect::to("/login").into_response()),
};
let folder_filter = q
.folder
.as_ref()
.map(|s| s.trim())
.filter(|s| !s.is_empty())
.map(|s| s.to_string());
let type_filter = q
.entry_type
.as_ref()
.map(|s| s.trim())
.filter(|s| !s.is_empty())
.map(|s| s.to_string());
let params = SearchParams {
folder: None,
entry_type: None,
folder: folder_filter.as_deref(),
entry_type: type_filter.as_deref(),
name: None,
tags: &[],
query: None,
@@ -567,6 +591,8 @@ async fn entries_page(
total_count,
shown_count,
limit: ENTRIES_PAGE_LIMIT,
filter_folder: folder_filter.unwrap_or_default(),
filter_type: type_filter.unwrap_or_default(),
version: env!("CARGO_PKG_VERSION"),
};