feat: add evidence search and stabilize pdf previews

- add document evidence parsing/search/open routes, Hermes tool wiring, local index settings/status, and the document-evidence skill plus design notes
- fix PDF resource tabs by rendering PDFs inline with pdf.js canvases instead of iframe preview pages, release PDF documents on close, and document the fourth-PDF stall bug
- keep PDF preview at 2x rendering while removing the previous lazy-load/placeholder direction, and make dev:hot bind loopback defaults externally reachable

Verification:
- node --check rust/crates/mnote-web/browser/document-resource-tab-runtime.js
- node scripts/task-dev-hot-plan-test.js
- cargo test -p mnote-web --manifest-path rust/Cargo.toml pdf_preview_page_does_not_render_visible_toolbar
- cargo test -p mnote-web --manifest-path rust/Cargo.toml document_shell_returns_page_aggregate_snapshot
- cargo build -p mnote-web --manifest-path rust/Cargo.toml
- browser smoke: sequentially opened the four tea_seed_oil_cosmetic PDFs; fourth PDF rendered 15/15 canvases, iframeCount=0, browser errors=0
This commit is contained in:
lix-2026
2026-06-04 18:51:16 +08:00
parent 9f4b5c4d48
commit 627213dc01
51 changed files with 15960 additions and 1844 deletions
+39
View File
@@ -1604,6 +1604,45 @@ impl ControlPlaneStore for SqliteControlPlaneStore {
Ok(rows)
}
fn list_user_ui_preferences_for_scope(
&self,
workspace_id: Option<&str>,
source_kind: Option<&str>,
scope_kind: &str,
scope_id: &str,
key: &str,
) -> Result<Vec<UserUiPreferenceRecord>, ControlPlaneError> {
let workspace_id = workspace_id.map(str::trim).unwrap_or_default();
let source_kind = source_kind.map(str::trim).unwrap_or_default();
let scope_kind = scope_kind.trim();
let scope_id = scope_id.trim();
let key = key.trim();
if scope_kind.is_empty() || scope_id.is_empty() || key.is_empty() {
return Ok(Vec::new());
}
let conn = self.conn.lock().unwrap();
let mut stmt = conn.prepare(
"SELECT id, user_id, workspace_id, source_kind, scope_kind, scope_id, key,
value_json, status, created_at, updated_at, revision
FROM user_ui_preferences
WHERE status = 'active'
AND workspace_id = ?1
AND source_kind = ?2
AND scope_kind = ?3
AND scope_id = ?4
AND key = ?5
ORDER BY updated_at ASC",
)?;
let rows = stmt
.query_map(
params![workspace_id, source_kind, scope_kind, scope_id, key],
row_to_user_ui_preference,
)?
.collect::<Result<Vec<_>, _>>()
.map_err(ControlPlaneError::from)?;
Ok(rows)
}
fn ensure_ai_agent_profile_policy(
&self,
user_id: &str,
+9
View File
@@ -138,6 +138,15 @@ pub trait ControlPlaneStore: Send + Sync {
source_kind: Option<&str>,
) -> Result<Vec<UserUiPreferenceRecord>, ControlPlaneError>;
fn list_user_ui_preferences_for_scope(
&self,
workspace_id: Option<&str>,
source_kind: Option<&str>,
scope_kind: &str,
scope_id: &str,
key: &str,
) -> Result<Vec<UserUiPreferenceRecord>, ControlPlaneError>;
fn ensure_ai_agent_profile_policy(
&self,
user_id: &str,