feat(secrets-mcp): /entries 按 tags 筛选,发版 0.5.27
All checks were successful
Secrets MCP — Build & Release / 检查 / 构建 / 发版 (push) Successful in 5m48s
Secrets MCP — Build & Release / 部署 secrets-mcp (push) Successful in 5s

- Web:tags 查询参数、folder 计数 SQL、分页与 tab 保留 tags;模板与 i18n
- README / AGENTS / CHANGELOG;plans/web-tags-filter 等计划文档
This commit is contained in:
voson
2026-04-11 21:38:26 +08:00
parent 43d6164a15
commit f86d12b80e
11 changed files with 364 additions and 113 deletions

View File

@@ -23,7 +23,7 @@ Add a new `metadata_query` filter to `SearchParams` that uses PostgreSQL `jsonb_
#### secrets-core
**`crates/secrets-core/src/service/search.rs`**
`**crates/secrets-core/src/service/search.rs`**
- Add `metadata_query: Option<&'a str>` field to `SearchParams`
- In `entry_where_clause_and_next_idx`, when `metadata_query` is set, add:
@@ -42,7 +42,7 @@ EXISTS (
#### secrets-mcp (MCP tools)
**`crates/secrets-mcp/src/tools.rs`**
`**crates/secrets-mcp/src/tools.rs**`
- Add `metadata_query` field to `FindInput`:
@@ -56,7 +56,7 @@ metadata_query: Option<String>,
#### secrets-mcp (Web)
**`crates/secrets-mcp/src/web/entries.rs`**
`**crates/secrets-mcp/src/web/entries.rs**`
- Add `metadata_query: Option<String>` to `EntriesQuery`
- Thread it into all `SearchParams` usages (count, list, folder counts)
@@ -64,17 +64,19 @@ metadata_query: Option<String>,
- Add `metadata_query` to `EntriesPageTemplate` and filter form hidden fields
- Include `metadata_query` in pagination `href` links
**`crates/secrets-mcp/templates/entries.html`**
`**crates/secrets-mcp/templates/entries.html**`
- Add a "metadata 值" text input to the filter bar (after name, before type)
- Preserve value in the input on re-render
### i18n Keys
| Key | zh | zh-Hant | en |
|-----|-----|---------|-----|
| `filterMetaLabel` | 元数据值 | 元数据值 | Metadata value |
| `filterMetaPlaceholder` | 搜索元数据值 | 搜尋元資料值 | Search metadata values |
| Key | zh | zh-Hant | en |
| ----------------------- | ------ | ------- | ---------------------- |
| `filterMetaLabel` | 元数据值 | 元数据值 | Metadata value |
| `filterMetaPlaceholder` | 搜索元数据值 | 搜尋元資料值 | Search metadata values |
### Performance Notes
@@ -191,81 +193,76 @@ pub async fn get_relations_for_entries(
) -> Result<HashMap<Uuid, Vec<RelationSummary>>>
```
**`crates/secrets-core/src/service/mod.rs`** — add `pub mod relations;`
`**crates/secrets-core/src/service/mod.rs**` — add `pub mod relations;`
**`crates/secrets-core/src/db.rs`** — add entry_relations table creation in `migrate()`
`**crates/secrets-core/src/db.rs**` — add entry_relations table creation in `migrate()`
**`crates/secrets-core/src/error.rs`** — no new error variant needed; use `AppError::Validation { message }` for cycle detection and permission errors
`**crates/secrets-core/src/error.rs**` — no new error variant needed; use `AppError::Validation { message }` for cycle detection and permission errors
### MCP Tool Changes
**`crates/secrets-mcp/src/tools.rs`**
`**crates/secrets-mcp/src/tools.rs**`
1. **`secrets_add`** (`AddInput`): add optional `parent_ids: Option<Vec<String>>` field
- Description: "UUIDs of parent entries to link. Creates parent→child relations."
- After creating the entry, call `relations::add_relation` for each parent
2. **`secrets_update`** (`UpdateInput`): add two fields:
- `add_parent_ids: Option<Vec<String>>` — "UUIDs of parent entries to link"
- `remove_parent_ids: Option<Vec<String>>` — "UUIDs of parent entries to unlink"
3. **`secrets_find`** and `secrets_search` output: add `parents` and `children` arrays to each entry result:
```json
1. `**secrets_add**` (`AddInput`): add optional `parent_ids: Option<Vec<String>>` field
- Description: "UUIDs of parent entries to link. Creates parent→child relations."
- After creating the entry, call `relations::add_relation` for each parent
2. `**secrets_update**` (`UpdateInput`): add two fields:
- `add_parent_ids: Option<Vec<String>>` — "UUIDs of parent entries to link"
- `remove_parent_ids: Option<Vec<String>>` — "UUIDs of parent entries to unlink"
3. `**secrets_find**` and `secrets_search` output: add `parents` and `children` arrays to each entry result:
```json
{
"id": "...",
"name": "...",
"parents": [{"id": "...", "name": "...", "folder": "...", "type": "..."}],
"children": [{"id": "...", "name": "...", "folder": "...", "type": "..."}]
}
```
- Fetch relations for all returned entry IDs in a single batch query
```
- Fetch relations for all returned entry IDs in a single batch query
### Web Changes
**`crates/secrets-mcp/src/web/entries.rs`**
`**crates/secrets-mcp/src/web/entries.rs**`
1. **New API endpoints:**
- `POST /api/entries/{id}/relations` — add parent relation
- Body: `{ "parent_id": "uuid" }`
- Validates same-user ownership and cycle detection
- `DELETE /api/entries/{id}/relations/{parent_id}` — remove parent relation
- `GET /api/entries/options?q=xxx` — lightweight search for parent selection modal
- Returns `[{ "id": "...", "name": "...", "folder": "...", "type": "..." }]`
- Used by the edit dialog's parent selection autocomplete
- `POST /api/entries/{id}/relations` — add parent relation
- Body: `{ "parent_id": "uuid" }`
- Validates same-user ownership and cycle detection
- `DELETE /api/entries/{id}/relations/{parent_id}` — remove parent relation
- `GET /api/entries/options?q=xxx` — lightweight search for parent selection modal
- Returns `[{ "id": "...", "name": "...", "folder": "...", "type": "..." }]`
- Used by the edit dialog's parent selection autocomplete
2. **Entry list template data** — include parent/child counts per entry row
3. `**api_entry_patch`** — extend `EntryPatchBody` with optional `parent_ids: Option<Vec<Uuid>>`
- When present, replace all parent relations for this entry with the given list
- This is simpler than incremental add/remove in the Web UI context
3. **`api_entry_patch`** — extend `EntryPatchBody` with optional `parent_ids: Option<Vec<Uuid>>`
- When present, replace all parent relations for this entry with the given list
- This is simpler than incremental add/remove in the Web UI context
**`crates/secrets-mcp/templates/entries.html`**
`**crates/secrets-mcp/templates/entries.html**`
1. **List table**: add a "关联" (relations) column showing parent/child counts as clickable chips
2. **Edit dialog**: add "上级条目" (parent entries) section
- Show current parents as removable chips
- Add a search-as-you-type input that queries `/api/entries/options`
- Click a search result to add it as parent
- On save, send `parent_ids` in the PATCH body
- Show current parents as removable chips
- Add a search-as-you-type input that queries `/api/entries/options`
- Click a search result to add it as parent
- On save, send `parent_ids` in the PATCH body
3. **View dialog / detail**: show "下级条目" (children) list with clickable links that navigate to the child entry
4. **i18n**: add keys for all new UI elements
### i18n Keys (Entry Relations)
| Key | zh | zh-Hant | en |
|-----|-----|---------|-----|
| `colRelations` | 关联 | 關聯 | Relations |
| `parentEntriesLabel` | 上级条目 | 上級條目 | Parent entries |
| `childrenEntriesLabel` | 级条目 | 級條目 | Child entries |
| `addParentLabel` | 添加上级 | 新增上級 | Add parent |
| `removeParentLabel` | 移除上级 | 移除上級 | Remove parent |
| `searchEntriesPlaceholder` | 搜索条目… | 搜尋條目… | Search entries… |
| `noParents` | 无上级 | 無上級 | No parents |
| `noChildren` | 无级 | 無| No children |
| `relationCycleError` | 无法添加:会形成循环引用 | 無法新增:會形成循環引用 | Cannot add: would create a cycle |
| Key | zh | zh-Hant | en |
| -------------------------- | ------------ | ------------ | -------------------------------- |
| `colRelations` | 关联 | 關聯 | Relations |
| `parentEntriesLabel` | 级条目 | 級條目 | Parent entries |
| `childrenEntriesLabel` | 下级条目 | 下級條目 | Child entries |
| `addParentLabel` | 添加上级 | 新增上級 | Add parent |
| `removeParentLabel` | 移除上级 | 移除上級 | Remove parent |
| `searchEntriesPlaceholder` | 搜索条目… | 搜尋條目… | Search entries… |
| `noParents` | 无 | 無 | No parents |
| `noChildren` | 无下级 | 無下級 | No children |
| `relationCycleError` | 无法添加:会形成循环引用 | 無法新增:會形成循環引用 | Cannot add: would create a cycle |
### Audit Logging
@@ -276,7 +273,7 @@ Log relation changes in the existing `audit::log_tx` system:
### Export / Import
**`ExportEntry`** — add optional `parents: Vec<ParentRef>` where:
`**ExportEntry`** — add optional `parents: Vec<ParentRef>` where:
```rust
pub struct ParentRef {
@@ -368,25 +365,28 @@ This is idempotent (uses `IF NOT EXISTS`) and will run automatically on next sta
## Testing Checklist
### Metadata Search
- [ ] `metadata_query=1.2.3.4` matches entries where any metadata value contains "1.2.3.4"
- [ ] `metadata_query=1.2.3.4` does NOT match entries where only the key contains "1.2.3.4"
- [ ] `metadata_query` works with nested metadata (e.g. `{"server": {"ip": "1.2.3.4"}}`)
- [ ] `metadata_query` combined with `folder`/`type`/`tags` filters works correctly
- [ ] `metadata_query` with special characters (`%`, `_`) is properly escaped
- [ ] Existing `query` parameter behavior is unchanged
- [ ] Web filter bar preserves `metadata_query` across pagination and folder tab clicks
- `metadata_query=1.2.3.4` matches entries where any metadata value contains "1.2.3.4"
- `metadata_query=1.2.3.4` does NOT match entries where only the key contains "1.2.3.4"
- `metadata_query` works with nested metadata (e.g. `{"server": {"ip": "1.2.3.4"}}`)
- `metadata_query` combined with `folder`/`type`/`tags` filters works correctly
- `metadata_query` with special characters (`%`, `_`) is properly escaped
- Existing `query` parameter behavior is unchanged
- Web filter bar preserves `metadata_query` across pagination and folder tab clicks
### Entry Relations
- [ ] Can add a parent→child relation between two entries
- [ ] Can add multiple parents to a single entry
- [ ] Cannot add self-referencing relation (CHECK constraint)
- [ ] Cannot create a direct cycle (A→B→A)
- [ ] Cannot create an indirect cycle (A→B→C→A)
- [ ] Cannot link entries from different users
- [ ] Deleting an entry removes all its relation edges but leaves related entries intact
- [ ] MCP `secrets_add` with `parent_ids` creates relations
- [ ] MCP `secrets_update` with `add_parent_ids`/`remove_parent_ids` modifies relations
- [ ] MCP `secrets_find`/`secrets_search` output includes `parents` and `children`
- [ ] Web entry list shows relation counts
- [ ] Web edit dialog allows adding/removing parents
- [ ] Web entry view shows children with navigation links
- Can add a parent→child relation between two entries
- Can add multiple parents to a single entry
- Cannot add self-referencing relation (CHECK constraint)
- Cannot create a direct cycle (A→B→A)
- Cannot create an indirect cycle (A→B→C→A)
- Cannot link entries from different users
- Deleting an entry removes all its relation edges but leaves related entries intact
- MCP `secrets_add` with `parent_ids` creates relations
- MCP `secrets_update` with `add_parent_ids`/`remove_parent_ids` modifies relations
- MCP `secrets_find`/`secrets_search` output includes `parents` and `children`
- Web entry list shows relation counts
- Web edit dialog allows adding/removing parents
- Web entry view shows children with navigation links