fix(KAN-65): synchronize update menu and remove dock badge
CI/CD / preconditions (pull_request) Successful in 2s
Native JavaScript checks / Native launcher and release tests (pull_request) Successful in 1m4s
macOS checks / Native Rust tests and unsigned build (pull_request) Successful in 1m37s
CI/CD / Publish immutable image (pull_request) Canceled after 0s
CI/CD / test_and_check_app (pull_request) Canceled after 1m38s

This commit is contained in:
2026-09-28 08:01:35 +02:00
parent 4ee047311f
commit 4f9bf2dec4
5 changed files with 48 additions and 9 deletions
+1 -1
View File
@@ -308,7 +308,7 @@ pub fn builder() -> tauri::Builder<tauri::Wry> {
})); }));
let menu = MenuBuilder::new(app) let menu = MenuBuilder::new(app)
.item( .item(
&SubmenuBuilder::new(app, en::APP_NAME) &SubmenuBuilder::with_id(app, "app-menu", en::APP_NAME)
.about_with_text( .about_with_text(
en::ABOUT, en::ABOUT,
Some(about_metadata(app.package_info().version.to_string())), Some(about_metadata(app.package_info().version.to_string())),
+3
View File
@@ -20,6 +20,9 @@ pub use desktop::{builder, context};
#[cfg(target_os = "ios")] #[cfg(target_os = "ios")]
pub use ios::{builder, context}; 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)] #[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() { pub fn run() {
builder().run(context()).expect("Could not start KanbanGit"); builder().run(context()).expect("Could not start KanbanGit");
-1
View File
@@ -2,7 +2,6 @@ pub mod en {
pub const ABOUT: &str = "About KanbanGit"; pub const ABOUT: &str = "About KanbanGit";
pub const CHECK_UPDATES: &str = "Check For Updates…"; pub const CHECK_UPDATES: &str = "Check For Updates…";
pub const INSTALL_UPDATE: &str = "Install Update…"; pub const INSTALL_UPDATE: &str = "Install Update…";
pub const UPDATE_BADGE: &str = "Update";
pub const UPDATES: &str = "KanbanGit Updates"; pub const UPDATES: &str = "KanbanGit Updates";
pub const APP_NAME: &str = "KanbanGit"; pub const APP_NAME: &str = "KanbanGit";
pub const SERVER_SETTINGS: &str = "Server settings…"; pub const SERVER_SETTINGS: &str = "Server settings…";
+15 -6
View File
@@ -123,19 +123,28 @@ fn trusted_navigation(url: &Url) -> bool {
&& url.username().is_empty() && url.username().is_empty()
&& url.password().is_none() && 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) { pub fn refresh(app: &AppHandle) {
let (view, available, busy) = { let (view, available, busy) = {
let state = app.state::<Mutex<State>>(); let state = app.state::<Mutex<State>>();
let state = state.lock().unwrap(); let state = state.lock().unwrap();
(state.view.clone(), state.update.is_some(), state.busy()) (state.view.clone(), state.update.is_some(), state.busy())
}; };
if let Some(menu) = app.menu().and_then(|m| m.get("install-update")) { refresh_menu(app, available, busy);
if let Some(item) = menu.as_menuitem() {
let _ = item.set_enabled(available && !busy);
}
}
if let Some(window) = app.get_webview_window("updates") { 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) { if let Ok(json) = serde_json::to_string(&view) {
let _ = window.eval(format!("window.updateStatus?.({json})")); let _ = window.eval(format!("window.updateStatus?.({json})"));
} }
+29 -1
View File
@@ -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")] #[cfg(target_os = "macos")]
#[tauri::command] #[tauri::command]
fn updater_smoke_report(app: tauri::AppHandle, passed: bool, reason: String) { fn updater_smoke_report(app: tauri::AppHandle, passed: bool, reason: String) {
@@ -36,6 +60,7 @@ fn main() {
const $ = id => document.getElementById(id); const $ = id => document.getElementById(id);
for (let i = 0; i < 100 && !$('installed').textContent; i++) await new Promise(r => setTimeout(r, 50)); 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); 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 } }; 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); window.updateStatus(state);
if (!$('installed').textContent.includes('0.1.2 (build 2)') || !$('install').hidden || $('check').disabled) throw new Error('Current version state failed'); 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()); context.config_mut().identifier = format!("de.kanbangit.smoke.updates.{}", std::process::id());
let app = kanbangit_native::builder() let app = kanbangit_native::builder()
.manage(passed.clone()) .manage(passed.clone())
.invoke_handler(tauri::generate_handler![updater_smoke_report]) .invoke_handler(tauri::generate_handler![
updater_smoke_report,
updater_smoke_menu
])
.plugin(plugin) .plugin(plugin)
.build(context) .build(context)
.expect("App must start"); .expect("App must start");