From 4f9bf2dec4d69c946c67b3ed83f568183e06811d Mon Sep 17 00:00:00 2001 From: Twyco Date: Mon, 28 Sep 2026 08:01:35 +0200 Subject: [PATCH] fix(KAN-65): synchronize update menu and remove dock badge --- native/src-tauri/src/desktop.rs | 2 +- native/src-tauri/src/lib.rs | 3 +++ native/src-tauri/src/locale.rs | 1 - native/src-tauri/src/updates.rs | 21 ++++++++++++----- native/src-tauri/tests/updater_smoke.rs | 30 ++++++++++++++++++++++++- 5 files changed, 48 insertions(+), 9 deletions(-) diff --git a/native/src-tauri/src/desktop.rs b/native/src-tauri/src/desktop.rs index 0798424..3a3ee98 100644 --- a/native/src-tauri/src/desktop.rs +++ b/native/src-tauri/src/desktop.rs @@ -308,7 +308,7 @@ pub fn builder() -> tauri::Builder { })); let menu = MenuBuilder::new(app) .item( - &SubmenuBuilder::new(app, en::APP_NAME) + &SubmenuBuilder::with_id(app, "app-menu", en::APP_NAME) .about_with_text( en::ABOUT, Some(about_metadata(app.package_info().version.to_string())), diff --git a/native/src-tauri/src/lib.rs b/native/src-tauri/src/lib.rs index 75b1184..0fa255f 100644 --- a/native/src-tauri/src/lib.rs +++ b/native/src-tauri/src/lib.rs @@ -20,6 +20,9 @@ pub use desktop::{builder, context}; #[cfg(target_os = "ios")] pub use ios::{builder, context}; +#[cfg(all(target_os = "macos", feature = "smoke-test"))] +pub use updates::refresh_menu as refresh_update_menu_for_smoke_test; + #[cfg_attr(mobile, tauri::mobile_entry_point)] pub fn run() { builder().run(context()).expect("Could not start KanbanGit"); diff --git a/native/src-tauri/src/locale.rs b/native/src-tauri/src/locale.rs index 9330aa4..0b9cd36 100644 --- a/native/src-tauri/src/locale.rs +++ b/native/src-tauri/src/locale.rs @@ -2,7 +2,6 @@ pub mod en { pub const ABOUT: &str = "About KanbanGit"; pub const CHECK_UPDATES: &str = "Check For Updates…"; pub const INSTALL_UPDATE: &str = "Install Update…"; - pub const UPDATE_BADGE: &str = "Update"; pub const UPDATES: &str = "KanbanGit Updates"; pub const APP_NAME: &str = "KanbanGit"; pub const SERVER_SETTINGS: &str = "Server settings…"; diff --git a/native/src-tauri/src/updates.rs b/native/src-tauri/src/updates.rs index 7a59b4b..b7dd173 100644 --- a/native/src-tauri/src/updates.rs +++ b/native/src-tauri/src/updates.rs @@ -123,19 +123,28 @@ fn trusted_navigation(url: &Url) -> bool { && url.username().is_empty() && url.password().is_none() } +pub fn refresh_menu(app: &AppHandle, available: bool, busy: bool) { + if let Some(menu) = app + .menu() + .and_then(|menu| menu.get("app-menu")) + .and_then(|item| { + item.as_submenu() + .and_then(|menu| menu.get("install-update")) + }) + { + if let Some(item) = menu.as_menuitem() { + let _ = item.set_enabled(available && !busy); + } + } +} pub fn refresh(app: &AppHandle) { let (view, available, busy) = { let state = app.state::>(); let state = state.lock().unwrap(); (state.view.clone(), state.update.is_some(), state.busy()) }; - if let Some(menu) = app.menu().and_then(|m| m.get("install-update")) { - if let Some(item) = menu.as_menuitem() { - let _ = item.set_enabled(available && !busy); - } - } + refresh_menu(app, available, busy); if let Some(window) = app.get_webview_window("updates") { - let _ = window.set_badge_label(available.then(|| crate::locale::en::UPDATE_BADGE.into())); if let Ok(json) = serde_json::to_string(&view) { let _ = window.eval(format!("window.updateStatus?.({json})")); } diff --git a/native/src-tauri/tests/updater_smoke.rs b/native/src-tauri/tests/updater_smoke.rs index 4cfd397..8a5000f 100644 --- a/native/src-tauri/tests/updater_smoke.rs +++ b/native/src-tauri/tests/updater_smoke.rs @@ -1,3 +1,27 @@ +#[cfg(target_os = "macos")] +#[tauri::command] +fn updater_smoke_menu(app: tauri::AppHandle) -> Result<(), String> { + let submenu = app.menu().unwrap().get("app-menu").unwrap(); + let item = submenu.as_submenu().unwrap().get("install-update").unwrap(); + let item = item.as_menuitem().unwrap(); + for (available, busy, expected) in [ + (false, false, false), // No update. + (true, false, true), // Available update, also after a retryable failure. + (true, true, false), // Download or installation in progress. + (true, false, true), // Retry after a failed download. + (false, true, false), // A new check clears the previous update. + (false, false, false), // Up to date. + ] { + kanbangit_native::refresh_update_menu_for_smoke_test(&app, available, busy); + if item.is_enabled().map_err(|error| error.to_string())? != expected { + return Err(format!( + "Native install menu has wrong state: available={available}, busy={busy}" + )); + } + } + Ok(()) +} + #[cfg(target_os = "macos")] #[tauri::command] fn updater_smoke_report(app: tauri::AppHandle, passed: bool, reason: String) { @@ -36,6 +60,7 @@ fn main() { const $ = id => document.getElementById(id); for (let i = 0; i < 100 && !$('installed').textContent; i++) await new Promise(r => setTimeout(r, 50)); if ($('installed').textContent !== window.expectedInstalled) throw new Error('Actual installed version/build failed: ' + $('installed').textContent); + await window.__TAURI_INTERNALS__.invoke('updater_smoke_menu'); const state = { phase: 'current', currentVersion: '0.1.2', build: '2', version: null, notes: null, downloaded: 0, total: null, error: null, preferences: { automatic: true, intervalHours: 6 } }; window.updateStatus(state); if (!$('installed').textContent.includes('0.1.2 (build 2)') || !$('install').hidden || $('check').disabled) throw new Error('Current version state failed'); @@ -64,7 +89,10 @@ fn main() { context.config_mut().identifier = format!("de.kanbangit.smoke.updates.{}", std::process::id()); let app = kanbangit_native::builder() .manage(passed.clone()) - .invoke_handler(tauri::generate_handler![updater_smoke_report]) + .invoke_handler(tauri::generate_handler![ + updater_smoke_report, + updater_smoke_menu + ]) .plugin(plugin) .build(context) .expect("App must start");