diff --git a/Cargo.lock b/Cargo.lock index 95a43bc..b272177 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1968,7 +1968,7 @@ dependencies = [ [[package]] name = "secrets-mcp" -version = "0.3.4" +version = "0.3.5" dependencies = [ "anyhow", "askama", diff --git a/crates/secrets-mcp/Cargo.toml b/crates/secrets-mcp/Cargo.toml index 78968a4..76e00b6 100644 --- a/crates/secrets-mcp/Cargo.toml +++ b/crates/secrets-mcp/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "secrets-mcp" -version = "0.3.4" +version = "0.3.5" edition.workspace = true [[bin]] diff --git a/crates/secrets-mcp/src/web.rs b/crates/secrets-mcp/src/web.rs index dca409b..9ce6c48 100644 --- a/crates/secrets-mcp/src/web.rs +++ b/crates/secrets-mcp/src/web.rs @@ -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, + /// URL query key is `type` (maps to DB column `entries.type`). + #[serde(rename = "type")] + entry_type: Option, +} + // ── App state helpers ───────────────────────────────────────────────────────── fn google_cfg(state: &AppState) -> Option<&OAuthConfig> { @@ -510,6 +520,7 @@ async fn dashboard( async fn entries_page( State(state): State, session: Session, + Query(q): Query, ) -> Result { 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"), }; diff --git a/crates/secrets-mcp/templates/entries.html b/crates/secrets-mcp/templates/entries.html index 64678f3..fa3a7ec 100644 --- a/crates/secrets-mcp/templates/entries.html +++ b/crates/secrets-mcp/templates/entries.html @@ -48,6 +48,30 @@ padding: 24px; width: 100%; max-width: 1280px; margin: 0 auto; } .card-title { font-size: 20px; font-weight: 600; margin-bottom: 8px; } .card-subtitle { color: var(--text-muted); font-size: 13px; margin-bottom: 20px; } + .filter-bar { + display: flex; flex-wrap: wrap; align-items: flex-end; gap: 12px 16px; + margin-bottom: 20px; padding: 16px; background: var(--bg); border: 1px solid var(--border); + border-radius: 10px; + } + .filter-field { display: flex; flex-direction: column; gap: 6px; min-width: 140px; flex: 1; } + .filter-field label { font-size: 12px; color: var(--text-muted); font-weight: 500; } + .filter-field input { + background: var(--surface); border: 1px solid var(--border); border-radius: 6px; + color: var(--text); padding: 8px 10px; font-size: 13px; font-family: 'JetBrains Mono', monospace; + outline: none; width: 100%; + } + .filter-field input:focus { border-color: var(--accent); } + .filter-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; } + .btn-filter { + padding: 8px 16px; border-radius: 6px; border: none; background: var(--accent); color: #0d1117; + font-size: 13px; font-weight: 600; cursor: pointer; + } + .btn-filter:hover { background: var(--accent-hover); } + .btn-clear { + padding: 8px 14px; border-radius: 6px; border: 1px solid var(--border); background: transparent; + color: var(--text-muted); font-size: 13px; text-decoration: none; cursor: pointer; + } + .btn-clear:hover { background: var(--surface2); color: var(--text); } .empty { color: var(--text-muted); font-size: 14px; padding: 20px 0; } .table-wrap { overflow-x: auto; } table { width: 100%; border-collapse: collapse; min-width: 720px; } @@ -116,7 +140,22 @@
我的条目
-
{{ total_count }} 条记录;当前列表显示 {{ shown_count }} 条(按更新时间降序,单页最多 {{ limit }} 条)。不含密文字段。时间为浏览器本地时区。
+
在当前筛选条件下,共 {{ total_count }} 条记录;本页显示 {{ shown_count }} 条(按更新时间降序,单页最多 {{ limit }} 条)。不含密文字段。时间为浏览器本地时区。
+ +
+
+ + +
+
+ + +
+
+ + 清空 +
+
{% if entries.is_empty() %}
暂无条目。