From 0eeb45e16ecfc83d5bba5c8477ebb61dab1a19ff Mon Sep 17 00:00:00 2001 From: lucaronin Date: Tue, 3 Mar 2026 13:19:09 +0100 Subject: [PATCH] feat: add Check for Updates command to native menu and Cmd+K palette - Add APP_CHECK_FOR_UPDATES constant and menu item in menu.rs (between About and Settings) - Wire onCheckForUpdates handler through useMenuEvents and useAppCommands - Add test for app-check-for-updates dispatch --- src-tauri/src/menu.rs | 8 ++++++++ src/hooks/useAppCommands.ts | 1 + src/hooks/useMenuEvents.test.ts | 7 +++++++ src/hooks/useMenuEvents.ts | 2 ++ 4 files changed, 18 insertions(+) diff --git a/src-tauri/src/menu.rs b/src-tauri/src/menu.rs index 9fc9874e..40bc9df3 100644 --- a/src-tauri/src/menu.rs +++ b/src-tauri/src/menu.rs @@ -23,6 +23,7 @@ const NOTE_TRASH: &str = "note-trash"; const EDIT_FIND_IN_VAULT: &str = "edit-find-in-vault"; const VIEW_GO_BACK: &str = "view-go-back"; const VIEW_GO_FORWARD: &str = "view-go-forward"; +const APP_CHECK_FOR_UPDATES: &str = "app-check-for-updates"; const CUSTOM_IDS: &[&str] = &[ APP_SETTINGS, @@ -44,6 +45,7 @@ const CUSTOM_IDS: &[&str] = &[ VIEW_ZOOM_RESET, VIEW_GO_BACK, VIEW_GO_FORWARD, + APP_CHECK_FOR_UPDATES, ]; /// IDs of menu items that should be disabled when no note tab is active. @@ -56,10 +58,15 @@ fn build_app_menu(app: &App) -> MenuResult { .id(APP_SETTINGS) .accelerator("CmdOrCtrl+,") .build(app)?; + let check_updates_item = MenuItemBuilder::new("Check for Updates...") + .id(APP_CHECK_FOR_UPDATES) + .build(app)?; Ok(SubmenuBuilder::new(app, "Laputa") .about(None) .separator() + .item(&check_updates_item) + .separator() .item(&settings_item) .separator() .services() @@ -269,6 +276,7 @@ mod tests { "view-zoom-reset", "view-go-back", "view-go-forward", + "app-check-for-updates", ]; for id in &expected { assert!(CUSTOM_IDS.contains(id), "missing custom ID: {id}"); diff --git a/src/hooks/useAppCommands.ts b/src/hooks/useAppCommands.ts index b2972b2c..b4b29cee 100644 --- a/src/hooks/useAppCommands.ts +++ b/src/hooks/useAppCommands.ts @@ -122,6 +122,7 @@ export function useAppCommands(config: AppCommandsConfig): CommandAction[] { onSearch: config.onSearch, onGoBack: config.onGoBack, onGoForward: config.onGoForward, + onCheckForUpdates: config.onCheckForUpdates, activeTabPathRef: config.activeTabPathRef, handleCloseTabRef: config.handleCloseTabRef, activeTabPath: config.activeTabPath, diff --git a/src/hooks/useMenuEvents.test.ts b/src/hooks/useMenuEvents.test.ts index 2f06d78c..8cf81a4b 100644 --- a/src/hooks/useMenuEvents.test.ts +++ b/src/hooks/useMenuEvents.test.ts @@ -19,6 +19,7 @@ function makeHandlers(): MenuEventHandlers { onSearch: vi.fn(), onGoBack: vi.fn(), onGoForward: vi.fn(), + onCheckForUpdates: vi.fn(), activeTabPathRef: { current: '/vault/test.md' } as React.MutableRefObject, handleCloseTabRef: { current: vi.fn() } as React.MutableRefObject<(path: string) => void>, activeTabPath: '/vault/test.md', @@ -161,6 +162,12 @@ describe('dispatchMenuEvent', () => { expect(h.onGoForward).toHaveBeenCalled() }) + it('app-check-for-updates triggers check for updates', () => { + const h = makeHandlers() + dispatchMenuEvent('app-check-for-updates', h) + expect(h.onCheckForUpdates).toHaveBeenCalled() + }) + it('unknown event ID does nothing', () => { const h = makeHandlers() dispatchMenuEvent('unknown-event', h) diff --git a/src/hooks/useMenuEvents.ts b/src/hooks/useMenuEvents.ts index 06d0ec5f..bb898d44 100644 --- a/src/hooks/useMenuEvents.ts +++ b/src/hooks/useMenuEvents.ts @@ -19,6 +19,7 @@ export interface MenuEventHandlers { onSearch: () => void onGoBack?: () => void onGoForward?: () => void + onCheckForUpdates?: () => void activeTabPathRef: React.MutableRefObject handleCloseTabRef: React.MutableRefObject<(path: string) => void> activeTabPath: string | null @@ -58,6 +59,7 @@ function dispatchActiveTabEvent(id: string, h: MenuEventHandlers): boolean { function dispatchOptionalEvent(id: string, h: MenuEventHandlers): boolean { if (id === 'view-go-back') { h.onGoBack?.(); return true } if (id === 'view-go-forward') { h.onGoForward?.(); return true } + if (id === 'app-check-for-updates') { h.onCheckForUpdates?.(); return true } return false }