diff --git a/ui/desktop/src/App.tsx b/ui/desktop/src/App.tsx index fa79d6f6..973b4238 100644 --- a/ui/desktop/src/App.tsx +++ b/ui/desktop/src/App.tsx @@ -170,11 +170,19 @@ const PairRouteWrapper = ({ const SettingsRoute = () => { const location = useLocation(); const navigate = useNavigate(); + const [searchParams] = useSearchParams(); const setView = useNavigation(); - // Get viewOptions from location.state or history.state + // Get viewOptions from location.state, history.state, or URL search params const viewOptions = (location.state as SettingsViewOptions) || (window.history.state as SettingsViewOptions) || {}; + + // If section is provided via URL search params, add it to viewOptions + const sectionFromUrl = searchParams.get('section'); + if (sectionFromUrl) { + viewOptions.section = sectionFromUrl; + } + return navigate('/')} setView={setView} viewOptions={viewOptions} />; }; diff --git a/ui/desktop/src/components/settings/app/UpdateSection.tsx b/ui/desktop/src/components/settings/app/UpdateSection.tsx index daa42593..c694980e 100644 --- a/ui/desktop/src/components/settings/app/UpdateSection.tsx +++ b/ui/desktop/src/components/settings/app/UpdateSection.tsx @@ -1,4 +1,4 @@ -import { useState, useEffect } from 'react'; +import React, { useState, useEffect } from 'react'; import { Button } from '../../ui/button'; import { Loader2, Download, CheckCircle, AlertCircle } from 'lucide-react'; @@ -29,6 +29,9 @@ export default function UpdateSection() { currentVersion: '', }); const [progress, setProgress] = useState(0); + const [isUsingGitHubFallback, setIsUsingGitHubFallback] = useState(false); + const progressTimeoutRef = React.useRef | null>(null); + const lastProgressRef = React.useRef(0); // Track last progress to prevent backward jumps useEffect(() => { // Get current version on mount @@ -47,6 +50,11 @@ export default function UpdateSection() { } }); + // Check if using GitHub fallback + window.electron.isUsingGitHubFallback().then((isGitHub) => { + setIsUsingGitHubFallback(isGitHub); + }); + // Listen for updater events window.electron.onUpdaterEvent((event) => { console.log('Updater event:', event); @@ -63,6 +71,10 @@ export default function UpdateSection() { latestVersion: (event.data as UpdateEventData)?.version, isUpdateAvailable: true, })); + // Check if GitHub fallback is being used + window.electron.isUsingGitHubFallback().then((isGitHub) => { + setIsUsingGitHubFallback(isGitHub); + }); break; case 'update-not-available': @@ -73,10 +85,29 @@ export default function UpdateSection() { })); break; - case 'download-progress': + case 'download-progress': { setUpdateStatus('downloading'); - setProgress((event.data as UpdateEventData)?.percent || 0); + + // Get the new progress value (ensure it's a valid number) + const rawPercent = (event.data as UpdateEventData)?.percent; + const newProgress = typeof rawPercent === 'number' ? Math.round(rawPercent) : 0; + + // Only update if progress increased (prevents backward jumps from out-of-order events) + if (newProgress > lastProgressRef.current) { + lastProgressRef.current = newProgress; + + // Cancel any pending update + if (progressTimeoutRef.current) { + clearTimeout(progressTimeoutRef.current); + } + + // Use a small delay to batch rapid updates + progressTimeoutRef.current = setTimeout(() => { + setProgress(newProgress); + }, 50); // 50ms delay for smoother batching + } break; + } case 'update-downloaded': setUpdateStatus('ready'); @@ -93,11 +124,19 @@ export default function UpdateSection() { break; } }); + + // Cleanup timeout on unmount + return () => { + if (progressTimeoutRef.current) { + clearTimeout(progressTimeoutRef.current); + } + }; }, []); const checkForUpdates = async () => { setUpdateStatus('checking'); setProgress(0); + lastProgressRef.current = 0; // Reset progress tracking for new download try { const result = await window.electron.checkForUpdates(); @@ -123,29 +162,6 @@ export default function UpdateSection() { } }; - const downloadAndInstallUpdate = async () => { - setUpdateStatus('downloading'); - setProgress(0); - - try { - const result = await window.electron.downloadUpdate(); - - if (!result.success) { - throw new Error(result.error || 'Failed to download update'); - } - - // The download progress and completion will be handled by updater events - } catch (error) { - console.error('Error downloading update:', error); - setUpdateInfo((prev) => ({ - ...prev, - error: error instanceof Error ? error.message : 'Failed to download update', - })); - setUpdateStatus('error'); - setTimeout(() => setUpdateStatus('idle'), 5000); - } - }; - const installUpdate = () => { window.electron.installUpdate(); }; @@ -216,13 +232,6 @@ export default function UpdateSection() { Check for Updates - {updateInfo.isUpdateAvailable && updateStatus === 'idle' && ( - - )} - {updateStatus === 'ready' && (