import React, { useState, useEffect } from 'react'; import { motion } from 'framer-motion'; import { useSettings } from '~/lib/hooks/useSettings'; import { logStore } from '~/lib/stores/logs'; import { toast } from 'react-toastify'; import { Dialog, DialogRoot, DialogTitle, DialogDescription, DialogButton } from '~/components/ui/Dialog'; import { classNames } from '~/utils/classNames'; interface UpdateProgress { stage: 'fetch' | 'pull' | 'install' | 'build' | 'complete'; message: string; progress?: number; error?: string; details?: { changedFiles?: string[]; additions?: number; deletions?: number; commitMessages?: string[]; totalSize?: string; currentCommit?: string; remoteCommit?: string; }; } interface UpdateSettings { autoUpdate: boolean; notifyInApp: boolean; checkInterval: number; } const ProgressBar = ({ progress }: { progress: number }) => (
); const UpdateProgressDisplay = ({ progress }: { progress: UpdateProgress }) => (
{progress.message} {progress.progress}%
{progress.details && (
{progress.details.changedFiles && progress.details.changedFiles.length > 0 && (
Changed Files:
    {progress.details.changedFiles.map((file, index) => (
  • {file}
  • ))}
)} {progress.details.totalSize &&
Total size: {progress.details.totalSize}
} {progress.details.additions !== undefined && progress.details.deletions !== undefined && (
Changes: +{progress.details.additions}{' '} -{progress.details.deletions}
)} {progress.details.currentCommit && progress.details.remoteCommit && (
Updating from {progress.details.currentCommit} to {progress.details.remoteCommit}
)}
)}
); const UpdateTab = () => { const { isLatestBranch } = useSettings(); const [isChecking, setIsChecking] = useState(false); const [error, setError] = useState(null); const [updateSettings, setUpdateSettings] = useState(() => { const stored = localStorage.getItem('update_settings'); return stored ? JSON.parse(stored) : { autoUpdate: false, notifyInApp: true, checkInterval: 24, }; }); const [showUpdateDialog, setShowUpdateDialog] = useState(false); const [updateProgress, setUpdateProgress] = useState(null); useEffect(() => { localStorage.setItem('update_settings', JSON.stringify(updateSettings)); }, [updateSettings]); const checkForUpdates = async () => { console.log('Starting update check...'); setIsChecking(true); setError(null); setUpdateProgress(null); try { const branchToCheck = isLatestBranch ? 'main' : 'stable'; // Start the update check with streaming progress const response = await fetch('/api/update', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ branch: branchToCheck }), }); if (!response.ok) { throw new Error(`Update check failed: ${response.statusText}`); } const reader = response.body?.getReader(); if (!reader) { throw new Error('No response stream available'); } // Read the stream while (true) { const { done, value } = await reader.read(); if (done) { break; } // Convert the chunk to text and parse the JSON const chunk = new TextDecoder().decode(value); const lines = chunk.split('\n').filter(Boolean); for (const line of lines) { try { const progress = JSON.parse(line) as UpdateProgress; setUpdateProgress(progress); if (progress.error) { setError(progress.error); } // If we're done, update the UI accordingly if (progress.stage === 'complete') { setIsChecking(false); if (!progress.error) { // Update was successful toast.success('Update check completed'); if (progress.details?.changedFiles?.length) { setShowUpdateDialog(true); } } } } catch (e) { console.error('Error parsing progress update:', e); } } } } catch (error) { setError(error instanceof Error ? error.message : 'Unknown error occurred'); logStore.logWarning('Update Check Failed', { type: 'update', message: error instanceof Error ? error.message : 'Unknown error occurred', }); } finally { setIsChecking(false); } }; return (

Updates

Check for and manage application updates

{/* Update Settings Card */}

Update Settings

Automatic Updates

Automatically check and apply updates when available

In-App Notifications

Show notifications when updates are available

Check Interval

How often to check for updates

{/* Update Status Card */}

Update Status

{/* Show progress information */} {updateProgress && } {error &&
{error}
} {/* Update dialog */} Update Available {updateProgress?.details?.changedFiles && (

Changes:

    {updateProgress.details.changedFiles.map((file, index) => (
  • {file}
  • ))}
{updateProgress.details.totalSize && (

Total size: {updateProgress.details.totalSize}

)}
)}
setShowUpdateDialog(false)}> Cancel { setShowUpdateDialog(false); // Handle update initiation here }} > Update Now
); }; export default UpdateTab;