Compare commits
5
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d8a6bf0ce6 | ||
|
|
9e96111813 | ||
|
|
42efc01d58 | ||
|
|
dc93d5eab2 | ||
|
|
b21b9c225c |
@@ -13,6 +13,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/), and this
|
||||
|
||||
### Fixed
|
||||
|
||||
- Desktop tray notices, screenshot evidence, and grant prompts stay reusable after dismissal; screenshot evidence keeps the most recently selected image. (#606)
|
||||
- Proactive phone Thread messages render relay-token and host-path media as attachments while preserving multiline text; notification previews omit media markers. (#485)
|
||||
- Desktop computer screenshots attach validated image bytes to the host tool result instead of returning base64 as plain text.
|
||||
- Relay-owned media uploads are removed on token expiry, eviction, and shutdown; media activity logs omit tokens, file paths, and screenshot bytes.
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"$schema": "../gen/schemas/desktop-schema.json",
|
||||
"identifier": "secondary-windows",
|
||||
"description": "Dismiss the connection notice and screenshot evidence windows",
|
||||
"windows": ["notice", "evidence"],
|
||||
"permissions": ["core:window:allow-hide"]
|
||||
}
|
||||
@@ -2514,10 +2514,14 @@ mod app {
|
||||
label,
|
||||
event: WindowEvent::CloseRequested { api, .. },
|
||||
..
|
||||
} if label == "main" => {
|
||||
} if matches!(label.as_str(), "main" | "grant" | "notice" | "evidence") => {
|
||||
api.prevent_close();
|
||||
if let Some(window) = handle.get_webview_window("main") {
|
||||
request_main_hide(&window);
|
||||
if let Some(window) = handle.get_webview_window(&label) {
|
||||
if label == "main" {
|
||||
request_main_hide(&window);
|
||||
} else {
|
||||
let _ = window.hide();
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
|
||||
@@ -340,3 +340,47 @@ fn management_window_keeps_the_reviewed_compact_geometry() {
|
||||
assert!(ui.contains("hide().finally(() => setWindowVisible(true))"));
|
||||
assert!(ui.contains("document.visibilityState === 'visible'"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn secondary_windows_have_only_the_dismissal_permission() {
|
||||
let config: serde_json::Value =
|
||||
serde_json::from_str(include_str!("../tauri.conf.json")).unwrap();
|
||||
let main: serde_json::Value =
|
||||
serde_json::from_str(include_str!("../capabilities/default.json")).unwrap();
|
||||
let secondary: serde_json::Value =
|
||||
serde_json::from_str(include_str!("../capabilities/secondary-windows.json")).unwrap();
|
||||
|
||||
let configured: std::collections::BTreeSet<&str> = config["app"]["windows"]
|
||||
.as_array()
|
||||
.unwrap()
|
||||
.iter()
|
||||
.map(|window| window["label"].as_str().unwrap())
|
||||
.collect();
|
||||
let main_windows: std::collections::BTreeSet<&str> = main["windows"]
|
||||
.as_array()
|
||||
.unwrap()
|
||||
.iter()
|
||||
.map(|label| label.as_str().unwrap())
|
||||
.collect();
|
||||
let secondary_windows: std::collections::BTreeSet<&str> = secondary["windows"]
|
||||
.as_array()
|
||||
.unwrap()
|
||||
.iter()
|
||||
.map(|label| label.as_str().unwrap())
|
||||
.collect();
|
||||
|
||||
assert_eq!(main_windows, ["main", "grant"].into_iter().collect());
|
||||
assert_eq!(
|
||||
secondary_windows,
|
||||
["notice", "evidence"].into_iter().collect()
|
||||
);
|
||||
assert_eq!(
|
||||
configured,
|
||||
main_windows.union(&secondary_windows).copied().collect()
|
||||
);
|
||||
assert!(main_windows.is_disjoint(&secondary_windows));
|
||||
assert_eq!(
|
||||
secondary["permissions"],
|
||||
serde_json::json!(["core:window:allow-hide"])
|
||||
);
|
||||
}
|
||||
|
||||
@@ -286,16 +286,20 @@ function EvidenceWindow() {
|
||||
const [evidenceId, setEvidenceId] = useState<string | null>(null)
|
||||
const [source, setSource] = useState<string | null>(null)
|
||||
const [error, setError] = useState<string | null>(null)
|
||||
const requestGeneration = useRef(0)
|
||||
useEffect(() => {
|
||||
const receive = (event: Event) => {
|
||||
const id = (event as CustomEvent<{ evidenceId: string }>).detail.evidenceId
|
||||
const generation = ++requestGeneration.current
|
||||
setEvidenceId(id); setSource(null); setError(null)
|
||||
void call<string>('get_activity_screenshot', { evidenceId: id }).then(setSource).catch(value => setError(String(value)))
|
||||
void call<string>('get_activity_screenshot', { evidenceId: id })
|
||||
.then(value => { if (generation === requestGeneration.current) setSource(value) })
|
||||
.catch(value => { if (generation === requestGeneration.current) setError(String(value)) })
|
||||
}
|
||||
const close = (event: KeyboardEvent) => { if (event.key === 'Escape') void getCurrentWindow().hide() }
|
||||
window.addEventListener('hermes-screenshot-evidence', receive)
|
||||
window.addEventListener('keydown', close)
|
||||
return () => { window.removeEventListener('hermes-screenshot-evidence', receive); window.removeEventListener('keydown', close) }
|
||||
return () => { requestGeneration.current++; window.removeEventListener('hermes-screenshot-evidence', receive); window.removeEventListener('keydown', close) }
|
||||
}, [])
|
||||
return <div className="evidence-shell">
|
||||
<header><span><Eye /><strong>Screenshot evidence</strong><small>Stored locally with this activity event</small></span><button aria-label="Close screenshot" onClick={() => getCurrentWindow().hide()}><X /></button></header>
|
||||
|
||||
Reference in New Issue
Block a user