From 0a647cd6128cfe5c0ed8f19ce6aef85ac49a6be6 Mon Sep 17 00:00:00 2001 From: NimBold Date: Thu, 25 Jun 2026 02:03:19 +0330 Subject: [PATCH] fix: default logs off, suppress webview context menu, sort queue rows, defer keychain access to user action - Disable log capture by default in both backend (LOG_PAUSED=true) and frontend (isPaused=true) to avoid unnecessary disk I/O and battery drain. - Add a global contextmenu listener that prevents the webview's default right-click menu (Reload, etc.) so the app behaves like a native macOS window. Custom context menus in DownloadItem, LogsView, and Sidebar still work because their handlers preventDefault() before the document listener fires. - Sort the download table by queuePosition when viewing a specific queue so the move-up/down controls produce a visible reorder instead of a silent position swap with no UI feedback. - Rework the keychain access flow to eliminate the OS credential prompt that appeared before the app's own KeychainPermissionModal after every binary update. hydrate_extension_pairing_token now always skips the keychain; only the explicit Grant Access button (grant_keychain_access) triggers the OS prompt, which is user-initiated and therefore acceptable even when macOS trust resets after a code-signature change. --- src-tauri/src/db.rs | 1 + src-tauri/src/lib.rs | 9 +++++++-- src/components/DownloadTable.tsx | 26 ++++++++++++++++---------- src/main.tsx | 8 ++++++++ src/store/useSettingsStore.ts | 8 +++++--- src/utils/logger.ts | 2 +- 6 files changed, 38 insertions(+), 16 deletions(-) diff --git a/src-tauri/src/db.rs b/src-tauri/src/db.rs index 1016bf0..2f9f3f0 100644 --- a/src-tauri/src/db.rs +++ b/src-tauri/src/db.rs @@ -553,6 +553,7 @@ pub fn load_settings(connection: &Connection) -> Result, String> .map_err(|error| format!("failed to load settings: {error}")) } +#[allow(dead_code)] pub fn is_keychain_access_granted(connection: &Connection) -> Result { let Some(settings) = load_settings(connection)? else { return Ok(false); diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 4f8dcd1..abc516d 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -3435,7 +3435,12 @@ fn hydrate_extension_pairing_token( app_state: tauri::State<'_, AppState>, ) -> Result { let mut connection = database.lock()?; - let skip_keychain = !crate::db::is_keychain_access_granted(&connection).unwrap_or(false); + // Always skip the keychain during automatic hydration so the operating + // system never presents a credential-access prompt before the app's own + // modal is visible. The frontend will display the KeychainPermissionModal + // and only call grant_keychain_access — which touches the keychain — after + // the user explicitly clicks "Grant Access". + let skip_keychain = true; match crate::db::hydrate_pairing_token(&mut connection, skip_keychain) { Ok((token, token_changed)) => { if let Ok(mut pairing_token) = app_state.extension_pairing_token.write() { @@ -4210,7 +4215,7 @@ mod tests { } } -static LOG_PAUSED: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(false); +static LOG_PAUSED: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(true); #[tauri::command] fn toggle_log_pause(pause: bool) { diff --git a/src/components/DownloadTable.tsx b/src/components/DownloadTable.tsx index 29b0860..d2cc107 100644 --- a/src/components/DownloadTable.tsx +++ b/src/components/DownloadTable.tsx @@ -182,6 +182,12 @@ export const DownloadTable: React.FC = ({ filter }) => { default: return d.category === filter; } }); + + // Sort by queue position when viewing a specific queue so the visual + // order matches the queue order and move-up/down buttons reflect reality. + const sortedDownloads = filter.startsWith('queue:') + ? [...filteredDownloads].sort((left, right) => (left.queuePosition ?? 0) - (right.queuePosition ?? 0)) + : filteredDownloads; const handleItemClick = (e: React.MouseEvent, item: DownloadItem) => { if (e.metaKey || e.ctrlKey) { const newSelected = new Set(selectedIds); @@ -193,8 +199,8 @@ export const DownloadTable: React.FC = ({ filter }) => { setSelectedIds(newSelected); setLastSelectedId(item.id); } else if (e.shiftKey && lastSelectedId) { - const currentIndex = filteredDownloads.findIndex(d => d.id === item.id); - const lastIndex = filteredDownloads.findIndex(d => d.id === lastSelectedId); + const currentIndex = sortedDownloads.findIndex(d => d.id === item.id); + const lastIndex = sortedDownloads.findIndex(d => d.id === lastSelectedId); if (currentIndex !== -1 && lastIndex !== -1) { const start = Math.min(currentIndex, lastIndex); @@ -202,7 +208,7 @@ export const DownloadTable: React.FC = ({ filter }) => { const newSelected = new Set(selectedIds); for (let i = start; i <= end; i++) { - newSelected.add(filteredDownloads[i].id); + newSelected.add(sortedDownloads[i].id); } setSelectedIds(newSelected); } @@ -290,9 +296,9 @@ export const DownloadTable: React.FC = ({ filter }) => {