From 07c0aba883095052a2eeb170f65ed7dfdec5f8ed Mon Sep 17 00:00:00 2001 From: Jamie Pine Date: Fri, 30 Jan 2026 19:53:20 -0800 Subject: [PATCH] Refactor model download handling and improve progress tracking - Rearranged imports for consistency across components. - Enhanced the ModelManagement component to include detailed logging for download actions and errors. - Updated the ModelProgress component to connect to SSE only when actively downloading, preventing connection exhaustion. - Added a downloading state to the model status to indicate ongoing downloads. - Improved toast notifications for model downloads with completion and error callbacks. - Refactored the useModelDownloadToast hook to support new callbacks for download completion and error handling. - Updated backend model status to reflect downloading state during active downloads. --- app/src/App.tsx | 18 ++- app/src/components/History/HistoryTable.tsx | 19 ++- .../ServerSettings/ModelManagement.tsx | 143 +++++++++++------- .../ServerSettings/ModelProgress.tsx | 19 ++- app/src/hooks/useAutoUpdater.ts | 26 ++-- app/src/hooks/useAutoUpdater.tsx | 17 ++- app/src/lib/api/client.ts | 5 +- app/src/lib/api/models/ModelStatus.ts | 1 + app/src/lib/api/types.ts | 1 + app/src/lib/hooks/useModelDownloadToast.tsx | 59 +++++--- backend/main.py | 16 ++ backend/models.py | 1 + tauri/src-tauri/gen/Assets.car | Bin 3847048 -> 3847048 bytes 13 files changed, 223 insertions(+), 102 deletions(-) diff --git a/app/src/App.tsx b/app/src/App.tsx index 7ea797df..fbe29118 100644 --- a/app/src/App.tsx +++ b/app/src/App.tsx @@ -1,14 +1,14 @@ -import { useEffect, useRef, useState } from 'react'; import { RouterProvider } from '@tanstack/react-router'; +import { useEffect, useRef, useState } from 'react'; import voiceboxLogo from '@/assets/voicebox-logo.png'; import ShinyText from '@/components/ShinyText'; import { TitleBarDragRegion } from '@/components/TitleBarDragRegion'; +import { useAutoUpdater } from '@/hooks/useAutoUpdater'; import { TOP_SAFE_AREA_PADDING } from '@/lib/constants/ui'; import { cn } from '@/lib/utils/cn'; +import { usePlatform } from '@/platform/PlatformContext'; import { router } from '@/router'; import { useServerStore } from '@/stores/serverStore'; -import { usePlatform } from '@/platform/PlatformContext'; -import { useAutoUpdater } from '@/hooks/useAutoUpdater'; const LOADING_MESSAGES = [ 'Warming up tensors...', @@ -50,14 +50,18 @@ function App() { console.error('Failed to sync initial setting to Rust:', error); }); } - }, [platform]); + // Empty dependency array - platform is stable from context, only run once + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [platform.metadata.isTauri, platform.lifecycle]); // Setup lifecycle callbacks useEffect(() => { platform.lifecycle.onServerReady = () => { setServerReady(true); }; - }, [platform]); + // Empty dependency array - platform is stable from context, only run once + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [platform.lifecycle]); // Setup window close handler and auto-start server when running in Tauri (production only) useEffect(() => { @@ -115,7 +119,9 @@ function App() { // Window close event handles server shutdown based on setting serverStartingRef.current = false; }; - }, [platform]); + // Empty dependency array - platform is stable from context, only run once + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [platform.metadata.isTauri, platform.lifecycle]); // Cycle through loading messages every 3 seconds useEffect(() => { diff --git a/app/src/components/History/HistoryTable.tsx b/app/src/components/History/HistoryTable.tsx index 67abe80d..ac0f5170 100644 --- a/app/src/components/History/HistoryTable.tsx +++ b/app/src/components/History/HistoryTable.tsx @@ -1,6 +1,13 @@ -import { AudioWaveform, Download, FileArchive, Loader2, MoreHorizontal, Play, Trash2 } from 'lucide-react'; +import { + AudioWaveform, + Download, + FileArchive, + Loader2, + MoreHorizontal, + Play, + Trash2, +} from 'lucide-react'; import { useEffect, useRef, useState } from 'react'; -import type { HistoryResponse } from '@/lib/api/types'; import { Button } from '@/components/ui/button'; import { Dialog, @@ -19,6 +26,7 @@ import { import { Textarea } from '@/components/ui/textarea'; import { useToast } from '@/components/ui/use-toast'; import { apiClient } from '@/lib/api/client'; +import type { HistoryResponse } from '@/lib/api/types'; import { BOTTOM_SAFE_AREA_PADDING } from '@/lib/constants/ui'; import { useDeleteGeneration, @@ -48,7 +56,11 @@ export function HistoryTable() { const limit = 20; const { toast } = useToast(); - const { data: historyData, isLoading, isFetching } = useHistory({ + const { + data: historyData, + isLoading, + isFetching, + } = useHistory({ limit, offset: page * limit, }); @@ -265,6 +277,7 @@ export function HistoryTable() {