diff --git a/src/main/services/autoUpdater.ts b/src/main/services/autoUpdater.ts index d40abe9..75dae31 100644 --- a/src/main/services/autoUpdater.ts +++ b/src/main/services/autoUpdater.ts @@ -151,7 +151,7 @@ export class AutoUpdateService { }; private readonly notAvailableListener = () => { - this.publishStatus({ state: 'idle' }); + this.publishStatus({ state: 'up-to-date' }); }; private readonly progressListener = (progress: AutoUpdateProgressLike) => { diff --git a/src/renderer/components/SettingsPanel.tsx b/src/renderer/components/SettingsPanel.tsx index 2f84dfc..b478e02 100644 --- a/src/renderer/components/SettingsPanel.tsx +++ b/src/renderer/components/SettingsPanel.tsx @@ -1,5 +1,5 @@ import { useEffect, useState, type ReactNode } from 'react'; -import { ChevronLeft, ChevronRight, Code, Cpu, FolderOpen, Palette, Plus, RefreshCw, Server, TriangleAlert, Workflow, Wrench } from 'lucide-react'; +import { ChevronLeft, ChevronRight, CircleCheck, Code, Cpu, FolderOpen, Palette, Plus, RefreshCw, Server, TriangleAlert, Workflow, Wrench } from 'lucide-react'; import { CopilotStatusCard } from '@renderer/components/CopilotStatusCard'; import { PatternEditor } from '@renderer/components/PatternEditor'; @@ -859,6 +859,8 @@ function TroubleshootingSection({ switch (updateStatus.state) { case 'checking': return 'Checking for updates…'; + case 'up-to-date': + return 'Up to date'; case 'available': return `Update available: v${updateStatus.version ?? 'unknown'}`; case 'downloading': @@ -876,6 +878,8 @@ function TroubleshootingSection({ switch (updateStatus.state) { case 'checking': return 'Contacting the update server…'; + case 'up-to-date': + return 'You are running the latest version of Aryx.'; case 'available': case 'downloading': return 'A new version is being downloaded and will be installed automatically.'; @@ -922,11 +926,13 @@ function TroubleshootingSection({ onClick={() => void handleCheckForUpdates()} type="button" > - - + + {updateStatus.state === 'up-to-date' + ? + : }
- + {getUpdateLabel()}

{getUpdateDescription()}

diff --git a/src/shared/contracts/ipc.ts b/src/shared/contracts/ipc.ts index 51c0ea6..c30d47e 100644 --- a/src/shared/contracts/ipc.ts +++ b/src/shared/contracts/ipc.ts @@ -175,7 +175,7 @@ export interface SetTerminalHeightInput { height?: number; } -export type UpdateStatusState = 'idle' | 'checking' | 'available' | 'downloading' | 'downloaded' | 'error'; +export type UpdateStatusState = 'idle' | 'checking' | 'up-to-date' | 'available' | 'downloading' | 'downloaded' | 'error'; export interface UpdateDownloadProgress { bytesPerSecond: number; diff --git a/tests/main/autoUpdater.test.ts b/tests/main/autoUpdater.test.ts index 8b08926..2824956 100644 --- a/tests/main/autoUpdater.test.ts +++ b/tests/main/autoUpdater.test.ts @@ -148,6 +148,22 @@ describe('AutoUpdateService', () => { ]); }); + test('transitions to up-to-date when no update is available', () => { + const updater = new FakeUpdater(); + const service = new AutoUpdateService({ isPackaged: true, updater }); + const statuses: UpdateStatus[] = []; + service.onStatus((status) => statuses.push(status)); + + updater.emit('checking-for-update'); + updater.emit('update-not-available', {}); + + expect(statuses).toEqual([ + { state: 'checking' }, + { state: 'up-to-date' }, + ]); + expect(service.getStatus()).toEqual({ state: 'up-to-date' }); + }); + test('reports updater errors and only installs once an update is downloaded', () => { const updater = new FakeUpdater(); const service = new AutoUpdateService({ isPackaged: true, updater });