diff --git a/src/App.tsx b/src/App.tsx index fc3c8016..6cb7dee3 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -24,7 +24,7 @@ import { useAppCommands } from './hooks/useAppCommands' import { useDialogs } from './hooks/useDialogs' import { useVaultSwitcher } from './hooks/useVaultSwitcher' import { useGitHistory } from './hooks/useGitHistory' -import { useUpdater } from './hooks/useUpdater' +import { useUpdater, restartApp } from './hooks/useUpdater' import { useNavigationHistory } from './hooks/useNavigationHistory' import { useAutoSync } from './hooks/useAutoSync' import { useConflictResolver } from './hooks/useConflictResolver' @@ -280,6 +280,14 @@ function App() { const { status: updateStatus, actions: updateActions } = useUpdater() const handleCheckForUpdates = useCallback(async () => { + if (updateStatus.state === 'downloading') { + setToastMessage('Update is downloading…') + return + } + if (updateStatus.state === 'ready') { + await restartApp() + return + } const result = await updateActions.checkForUpdates() if (result === 'up-to-date') { setToastMessage("You're on the latest version") @@ -287,7 +295,7 @@ function App() { setToastMessage('Could not check for updates') } // 'available' → UpdateBanner handles it automatically - }, [updateActions, setToastMessage]) + }, [updateActions, updateStatus.state, setToastMessage]) const commands = useAppCommands({ activeTabPath: notes.activeTabPath, activeTabPathRef: notes.activeTabPathRef, @@ -334,7 +342,6 @@ function App() { onCreateType: dialogs.openCreateType, onToggleAIChat: dialogs.toggleAIChat, onCheckForUpdates: handleCheckForUpdates, - isUpdating: updateStatus.state === 'downloading' || updateStatus.state === 'ready', onRemoveActiveVault: () => vaultSwitcher.removeVault(vaultSwitcher.vaultPath), onRestoreGettingStarted: vaultSwitcher.restoreGettingStarted, isGettingStartedHidden: vaultSwitcher.isGettingStartedHidden, diff --git a/src/hooks/useAppCommands.ts b/src/hooks/useAppCommands.ts index b4b29cee..e416ba71 100644 --- a/src/hooks/useAppCommands.ts +++ b/src/hooks/useAppCommands.ts @@ -60,7 +60,6 @@ interface AppCommandsConfig { onCreateType?: () => void onToggleAIChat?: () => void onCheckForUpdates?: () => void - isUpdating?: boolean onRemoveActiveVault?: () => void onRestoreGettingStarted?: () => void isGettingStartedHidden?: boolean @@ -169,7 +168,6 @@ export function useAppCommands(config: AppCommandsConfig): CommandAction[] { onCreateType: config.onCreateType, onToggleAIChat: config.onToggleAIChat, onCheckForUpdates: config.onCheckForUpdates, - isUpdating: config.isUpdating, onRemoveActiveVault: config.onRemoveActiveVault, onRestoreGettingStarted: config.onRestoreGettingStarted, isGettingStartedHidden: config.isGettingStartedHidden, diff --git a/src/hooks/useCommandRegistry.test.ts b/src/hooks/useCommandRegistry.test.ts index 7f0a1a78..91b9ed52 100644 --- a/src/hooks/useCommandRegistry.test.ts +++ b/src/hooks/useCommandRegistry.test.ts @@ -369,20 +369,11 @@ describe('useCommandRegistry', () => { expect(cmd!.keywords).toContain('version') }) - it('is enabled when not updating', () => { - const { result } = renderHook(() => - useCommandRegistry(makeConfig({ isUpdating: false })), - ) + it('is always enabled', () => { + const { result } = renderHook(() => useCommandRegistry(makeConfig())) expect(result.current.find(c => c.id === 'check-updates')!.enabled).toBe(true) }) - it('is disabled when updating', () => { - const { result } = renderHook(() => - useCommandRegistry(makeConfig({ isUpdating: true })), - ) - expect(result.current.find(c => c.id === 'check-updates')!.enabled).toBe(false) - }) - it('calls onCheckForUpdates when executed', () => { const onCheckForUpdates = vi.fn() const { result } = renderHook(() => diff --git a/src/hooks/useCommandRegistry.ts b/src/hooks/useCommandRegistry.ts index 1c8f9944..6aacd259 100644 --- a/src/hooks/useCommandRegistry.ts +++ b/src/hooks/useCommandRegistry.ts @@ -40,7 +40,6 @@ interface CommandRegistryConfig { onToggleAIChat?: () => void activeNoteModified: boolean onCheckForUpdates?: () => void - isUpdating?: boolean onZoomIn: () => void onZoomOut: () => void onZoomReset: () => void @@ -191,7 +190,7 @@ export function useCommandRegistry(config: CommandRegistryConfig): CommandAction onSelect, onOpenDailyNote, onCloseTab, onGoBack, onGoForward, canGoBack, canGoForward, themes, activeThemeId, onSwitchTheme, onCreateTheme, onOpenTheme, - onCheckForUpdates, isUpdating, + onCheckForUpdates, onCreateType, onRemoveActiveVault, onRestoreGettingStarted, isGettingStartedHidden, vaultCount, } = config @@ -252,7 +251,7 @@ export function useCommandRegistry(config: CommandRegistryConfig): CommandAction { id: 'open-vault', label: 'Open Vault…', group: 'Settings', keywords: ['vault', 'folder', 'switch', 'open', 'workspace'], enabled: true, execute: () => onOpenVault?.() }, { id: 'remove-vault', label: 'Remove Vault from List', group: 'Settings', keywords: ['vault', 'remove', 'disconnect', 'hide'], enabled: (vaultCount ?? 0) > 1 && !!onRemoveActiveVault, execute: () => onRemoveActiveVault?.() }, { id: 'restore-getting-started', label: 'Restore Getting Started Vault', group: 'Settings', keywords: ['vault', 'restore', 'demo', 'getting started', 'reset'], enabled: !!isGettingStartedHidden && !!onRestoreGettingStarted, execute: () => onRestoreGettingStarted?.() }, - { id: 'check-updates', label: 'Check for Updates', group: 'Settings', keywords: ['update', 'version', 'upgrade', 'release'], enabled: !isUpdating, execute: () => onCheckForUpdates?.() }, + { id: 'check-updates', label: 'Check for Updates', group: 'Settings', keywords: ['update', 'version', 'upgrade', 'release'], enabled: true, execute: () => onCheckForUpdates?.() }, // Type-aware: "New [Type]" and "List [Type]" ...buildTypeCommands(vaultTypes, onCreateNoteOfType, onSelect), @@ -264,7 +263,7 @@ export function useCommandRegistry(config: CommandRegistryConfig): CommandAction onQuickOpen, onCreateNote, onCreateNoteOfType, onCreateType, onSave, onOpenSettings, onTrashNote, onRestoreNote, onArchiveNote, onUnarchiveNote, onCommitPush, onResolveConflicts, onSetViewMode, onToggleInspector, onToggleDiff, onToggleRawEditor, onToggleAIChat, onOpenVault, - onCheckForUpdates, isUpdating, + onCheckForUpdates, onZoomIn, onZoomOut, onZoomReset, zoomLevel, onSelect, onOpenDailyNote, onCloseTab, onGoBack, onGoForward, canGoBack, canGoForward,