-
Notifications
You must be signed in to change notification settings - Fork 1
Add notes feature, sysinfo, and auth window (v0.5.0) #5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| <!-- Generated by SpecStory, Markdown v2.1.0 --> | ||
|
|
||
| <!-- cursor Session e1e9239a-c980-49bb-9d93-9a048b088b44 (2026-02-23 16:43Z) --> | ||
|
|
||
| # Produire une description de Pull Request pour la branche Git (2026-02-23 16:43Z) | ||
|
|
||
| _**User**_ | ||
|
|
||
| Produire une description de Pull Request pour la branche Git actuelle en analysant les derniers commit effectués sur celle-ci et en respectant les standards GitHub de nommage, syntaxe et formatage. Ne pas inclure de captures d'écrans et ne pas indiquer de clotures d'issue GitHub. | ||
|
|
||
| --- | ||
|
|
||
| _**Agent (model default, mode Agent)**_ | ||
|
|
||
|
|
||
|
|
||
| --- | ||
|
|
||
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -21,3 +21,4 @@ url = "2" | |
| open = "5.3.3" | ||
| tts = "0.26" | ||
| base64 = "0.22" | ||
| sysinfo = "0.32" | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -2,9 +2,11 @@ | |||||||||||||||||||||||||
| "$schema": "https://raw.githubusercontent.com/nicegui-org/nicegui/main/tauri-capabilities-schema.json", | ||||||||||||||||||||||||||
| "identifier": "default", | ||||||||||||||||||||||||||
| "description": "Capability for the main window", | ||||||||||||||||||||||||||
| "windows": ["main"], | ||||||||||||||||||||||||||
| "windows": ["main", "auth"], | ||||||||||||||||||||||||||
| "permissions": [ | ||||||||||||||||||||||||||
| "core:default", | ||||||||||||||||||||||||||
| "core:event:default", | ||||||||||||||||||||||||||
| "core:webview:allow-create-webview-window", | ||||||||||||||||||||||||||
| "core:window:allow-minimize", | ||||||||||||||||||||||||||
|
Comment on lines
+5
to
10
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Avoid granting default capabilities to the auth window. If the auth webview loads remote OAuth pages, inheriting 🔒 Suggested fix (remove auth from default capability)- "windows": ["main", "auth"],
+ "windows": ["main"],📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||
| "core:window:allow-toggle-maximize", | ||||||||||||||||||||||||||
| "core:window:allow-close", | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1 @@ | ||
| {"default":{"identifier":"default","description":"Capability for the main window","local":true,"windows":["main"],"permissions":["core:default","core:window:allow-minimize","core:window:allow-toggle-maximize","core:window:allow-close","core:window:allow-is-maximized","core:window:allow-start-dragging","core:window:allow-set-minimizable","core:window:allow-set-size","core:window:allow-inner-size","core:window:allow-set-min-size","core:window:allow-set-resizable","core:window:allow-outer-position","core:window:allow-set-position","core:window:allow-set-focus","core:window:allow-set-always-on-top","core:window:allow-set-effects"]}} | ||
| {"default":{"identifier":"default","description":"Capability for the main window","local":true,"windows":["main","auth"],"permissions":["core:default","core:event:default","core:webview:allow-create-webview-window","core:window:allow-minimize","core:window:allow-toggle-maximize","core:window:allow-close","core:window:allow-is-maximized","core:window:allow-start-dragging","core:window:allow-set-minimizable","core:window:allow-set-size","core:window:allow-inner-size","core:window:allow-set-min-size","core:window:allow-set-resizable","core:window:allow-outer-position","core:window:allow-set-position","core:window:allow-set-focus","core:window:allow-set-always-on-top","core:window:allow-set-effects"]}} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -261,6 +261,88 @@ async fn http_request( | |
| }) | ||
| } | ||
|
|
||
| #[tauri::command] | ||
| fn get_cpu_usage() -> f32 { | ||
| use sysinfo::System; | ||
| static SYS: OnceLock<Mutex<System>> = OnceLock::new(); | ||
| let mtx = SYS.get_or_init(|| { | ||
| let mut sys = System::new(); | ||
| sys.refresh_cpu_usage(); | ||
| Mutex::new(sys) | ||
| }); | ||
| let mut sys = mtx.lock().unwrap(); | ||
| sys.refresh_cpu_usage(); | ||
| sys.global_cpu_usage() | ||
|
Comment on lines
+267
to
+275
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 5. mtx.lock().unwrap() may panic The new sysinfo Tauri commands use unwrap() on mutex locks, which can crash the app if the mutex is poisoned or unavailable. This is a new failure mode without graceful error handling or fallback behavior. Agent Prompt
|
||
| } | ||
|
|
||
| #[derive(Serialize)] | ||
| struct MemoryInfo { | ||
| used_gb: f64, | ||
| total_gb: f64, | ||
| percent: f32, | ||
| } | ||
|
|
||
| #[tauri::command] | ||
| fn get_memory_usage() -> MemoryInfo { | ||
| use sysinfo::System; | ||
| let mut sys = System::new(); | ||
| sys.refresh_memory(); | ||
| let total = sys.total_memory() as f64; | ||
| let used = sys.used_memory() as f64; | ||
| let gb = 1_073_741_824.0; // 1 GiB | ||
| MemoryInfo { | ||
| used_gb: (used / gb * 10.0).round() / 10.0, | ||
| total_gb: (total / gb * 10.0).round() / 10.0, | ||
| percent: if total > 0.0 { (used / total * 100.0) as f32 } else { 0.0 }, | ||
| } | ||
| } | ||
|
|
||
| #[derive(Serialize)] | ||
| struct NetSpeed { | ||
| download_kbps: f64, | ||
| upload_kbps: f64, | ||
| } | ||
|
|
||
| #[tauri::command] | ||
| fn get_net_speed() -> NetSpeed { | ||
| use sysinfo::Networks; | ||
| use std::time::Instant; | ||
|
|
||
| static NET: OnceLock<Mutex<(Networks, Instant, u64, u64)>> = OnceLock::new(); | ||
| let mtx = NET.get_or_init(|| { | ||
| let mut nets = Networks::new_with_refreshed_list(); | ||
| nets.refresh(); | ||
| let (rx, tx) = nets.iter().fold((0u64, 0u64), |(r, t), (_name, data)| { | ||
| (r + data.total_received(), t + data.total_transmitted()) | ||
| }); | ||
| Mutex::new((nets, Instant::now(), rx, tx)) | ||
| }); | ||
|
|
||
| let mut guard = mtx.lock().unwrap(); | ||
| let (ref mut nets, ref mut last_time, ref mut last_rx, ref mut last_tx) = *guard; | ||
|
|
||
| nets.refresh(); | ||
| let now = Instant::now(); | ||
| let elapsed = now.duration_since(*last_time); | ||
| let secs = elapsed.as_secs_f64().max(0.1); | ||
|
|
||
| let (rx, tx) = nets.iter().fold((0u64, 0u64), |(r, t), (_name, data)| { | ||
| (r + data.total_received(), t + data.total_transmitted()) | ||
| }); | ||
|
|
||
| let dl = (rx.saturating_sub(*last_rx) as f64) / secs / 1024.0; // KB/s | ||
| let ul = (tx.saturating_sub(*last_tx) as f64) / secs / 1024.0; | ||
|
|
||
| *last_time = now; | ||
| *last_rx = rx; | ||
| *last_tx = tx; | ||
|
|
||
| NetSpeed { | ||
| download_kbps: (dl * 10.0).round() / 10.0, | ||
| upload_kbps: (ul * 10.0).round() / 10.0, | ||
| } | ||
| } | ||
|
|
||
| #[tauri::command] | ||
| fn open_external(url: String) -> Result<(), String> { | ||
| open::that(&url).map_err(|e| format!("Failed to open URL: {e}")) | ||
|
|
@@ -507,14 +589,51 @@ async fn tts_speak_elevenlabs( | |
| Ok(STANDARD.encode(&bytes)) | ||
| } | ||
|
|
||
| #[cfg(not(target_os = "android"))] | ||
| #[tauri::command] | ||
| async fn open_auth_window(app: tauri::AppHandle, url: String) -> Result<(), String> { | ||
| use tauri::{Emitter, WebviewUrl, WebviewWindowBuilder}; | ||
|
|
||
| // Close any existing auth window | ||
| if let Some(existing) = app.get_webview_window("auth") { | ||
| let _ = existing.close(); | ||
| } | ||
|
|
||
| let parsed_url: Url = url.parse().map_err(|e: url::ParseError| format!("Invalid URL: {e}"))?; | ||
| let app_handle = app.clone(); | ||
|
|
||
| WebviewWindowBuilder::new(&app, "auth", WebviewUrl::External(parsed_url)) | ||
| .title("Sign in") | ||
|
Comment on lines
+594
to
+606
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 4. open_auth_window accepts any url The new open_auth_window command builds an external webview window from a caller-provided URL without allowlisting/validation. This can enable opening arbitrary external content inside the app if the command is invoked with a malicious URL. Agent Prompt
|
||
| .inner_size(500.0, 700.0) | ||
| .on_navigation(move |nav_url| { | ||
| let url_str = nav_url.as_str(); | ||
| // Intercept redirect to our callback URL | ||
| if url_str.starts_with("http://localhost/auth/callback") { | ||
| let _ = app_handle.emit("auth-callback", url_str.to_string()); | ||
| return false; // Block navigation to localhost | ||
| } | ||
| true | ||
| }) | ||
| .build() | ||
| .map_err(|e| format!("Failed to create auth window: {e}"))?; | ||
|
|
||
| Ok(()) | ||
| } | ||
|
|
||
| #[cfg(target_os = "android")] | ||
| #[tauri::command] | ||
| async fn open_auth_window(_url: String) -> Result<(), String> { | ||
| Ok(()) | ||
|
Comment on lines
+623
to
+626
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 7. Android auth invoke mismatch On Android, the Rust open_auth_window command parameter is named _url, but the frontend invokes
it with { url: ... }. Tauri matches parameters by name, so OAuth will likely fail to open the auth
window on Android.
Agent Prompt
|
||
| } | ||
|
|
||
| #[cfg_attr(mobile, tauri::mobile_entry_point)] | ||
| pub fn run() { | ||
| tauri::Builder::default() | ||
| .manage(AppState { | ||
| #[cfg(not(target_os = "android"))] | ||
| saved: Mutex::new(None), | ||
| }) | ||
| .invoke_handler(tauri::generate_handler![fetch_url, http_request, open_external, collapse_window, expand_window, check_network, set_window_effect, tts_speak, tts_stop, tts_speak_elevenlabs]) | ||
| .invoke_handler(tauri::generate_handler![fetch_url, http_request, open_external, get_cpu_usage, get_memory_usage, get_net_speed, collapse_window, expand_window, check_network, set_window_effect, tts_speak, tts_stop, tts_speak_elevenlabs, open_auth_window]) | ||
| .setup(|_app| { | ||
| #[cfg(not(target_os = "android"))] | ||
| { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix minor French typos and phrasing.
These are small but user-visible text issues.
✍️ Suggested edits
📝 Committable suggestion
🧰 Tools
🪛 LanguageTool
[grammar] ~9-~9: Le mot « commits » est plus probable.
Context: ... Git actuelle en analysant les derniers commit effectués sur celle-ci et en respectant...
(QB_NEW_FR_OTHER_ERROR_IDS_REPLACEMENT_CONFUSION_COMMIT_COMMITS)
[grammar] ~9-~9: Utilisez les accents correctement
Context: ...captures d'écrans et ne pas indiquer de clotures d'issue GitHub. --- _**Agent (model d...
(QB_NEW_FR_OTHER_ERROR_IDS_MISSING_ORTHOGRAPHY_DIACRITIC_CIRCUMFLEX)
[grammar] ~13-~13: Essayez « modèle par défaut »
Context: ...lotures d'issue GitHub. --- Agent (model default, mode Agent) ---
(QB_NEW_FR_OTHER_ERROR_IDS_REPLACEMENT_MULTITOKEN)
[grammar] ~13-~13: Essayez « modèle par défaut »
Context: ...s d'issue GitHub. --- Agent (model default, mode Agent) ---
(QB_NEW_FR_OTHER_ERROR_IDS_REPLACEMENT_MULTITOKEN)
🤖 Prompt for AI Agents