diff --git a/app/src/components/StoriesTab/StoryContent.tsx b/app/src/components/StoriesTab/StoryContent.tsx index 89d6dbb1..0f53c2c9 100644 --- a/app/src/components/StoriesTab/StoryContent.tsx +++ b/app/src/components/StoriesTab/StoryContent.tsx @@ -58,6 +58,7 @@ export function StoryContent() { const query = searchQuery.toLowerCase(); return historyData.items.filter( (gen) => + gen.status === 'completed' && !storyGenerationIds.has(gen.id) && (gen.text.toLowerCase().includes(query) || gen.profile_name.toLowerCase().includes(query)), ); diff --git a/app/src/lib/hooks/useGenerationProgress.ts b/app/src/lib/hooks/useGenerationProgress.ts index c9f81c19..fa4820e1 100644 --- a/app/src/lib/hooks/useGenerationProgress.ts +++ b/app/src/lib/hooks/useGenerationProgress.ts @@ -8,7 +8,7 @@ import { useServerStore } from '@/stores/serverStore'; interface GenerationStatusEvent { id: string; - status: 'generating' | 'completed' | 'failed'; + status: 'generating' | 'completed' | 'failed' | 'not_found'; duration?: number; error?: string; } @@ -37,6 +37,17 @@ export function useGenerationProgress() { // Track active EventSource instances const eventSourcesRef = useRef>(new Map()); + // Unmount-only cleanup — close all SSE connections when the hook is torn down + useEffect(() => { + const sources = eventSourcesRef.current; + return () => { + for (const source of sources.values()) { + source.close(); + } + sources.clear(); + }; + }, []); + useEffect(() => { const currentSources = eventSourcesRef.current; @@ -103,7 +114,7 @@ export function useGenerationProgress() { const genAudioUrl = apiClient.getAudioUrl(id); setAudioWithAutoPlay(genAudioUrl, id, '', ''); } - } else if (data.status === 'failed') { + } else if (data.status === 'failed' || data.status === 'not_found') { source.close(); currentSources.delete(id); removePendingGeneration(id); @@ -112,7 +123,7 @@ export function useGenerationProgress() { queryClient.invalidateQueries({ queryKey: ['history'] }); toast({ - title: 'Generation failed', + title: data.status === 'not_found' ? 'Generation not found' : 'Generation failed', description: data.error || 'An error occurred during generation', variant: 'destructive', }); @@ -132,14 +143,6 @@ export function useGenerationProgress() { currentSources.set(id, source); } - - return () => { - // Cleanup on unmount - for (const source of currentSources.values()) { - source.close(); - } - currentSources.clear(); - }; }, [ pendingIds, removePendingGeneration, diff --git a/app/src/lib/hooks/useRestoreActiveTasks.tsx b/app/src/lib/hooks/useRestoreActiveTasks.tsx index 69c6ef9f..809cba03 100644 --- a/app/src/lib/hooks/useRestoreActiveTasks.tsx +++ b/app/src/lib/hooks/useRestoreActiveTasks.tsx @@ -15,7 +15,6 @@ const POLL_INTERVAL = 30000; */ export function useRestoreActiveTasks() { const [activeDownloads, setActiveDownloads] = useState([]); - const setIsGenerating = useGenerationStore((state) => state.setIsGenerating); const setActiveGenerationId = useGenerationStore((state) => state.setActiveGenerationId); const addPendingGeneration = useGenerationStore((state) => state.addPendingGeneration); @@ -26,18 +25,15 @@ export function useRestoreActiveTasks() { try { const tasks = await apiClient.getActiveTasks(); - // Update generation state — restore pending generations (e.g., after page refresh) + // Restore pending generations (e.g., after page refresh) if (tasks.generations.length > 0) { - setIsGenerating(true); setActiveGenerationId(tasks.generations[0].task_id); for (const gen of tasks.generations) { addPendingGeneration(gen.task_id); } } else { - // Only clear if we were tracking a generation const currentId = useGenerationStore.getState().activeGenerationId; if (currentId) { - setIsGenerating(false); setActiveGenerationId(null); } } @@ -63,7 +59,7 @@ export function useRestoreActiveTasks() { // Silently fail - server might be temporarily unavailable console.debug('Failed to fetch active tasks:', error); } - }, [setIsGenerating, setActiveGenerationId]); + }, [setActiveGenerationId, addPendingGeneration]); useEffect(() => { // Fetch immediately on mount diff --git a/app/src/stores/generationStore.ts b/app/src/stores/generationStore.ts index e791a992..edf715d1 100644 --- a/app/src/stores/generationStore.ts +++ b/app/src/stores/generationStore.ts @@ -3,7 +3,7 @@ import { create } from 'zustand'; interface GenerationState { /** IDs of generations currently in progress */ pendingGenerationIds: Set; - /** Whether any generation is in progress (derived convenience) */ + /** Whether any generation is in progress (derived from pendingGenerationIds) */ isGenerating: boolean; /** Map of generationId → storyId for deferred story additions */ pendingStoryAdds: Map; @@ -11,8 +11,6 @@ interface GenerationState { removePendingGeneration: (id: string) => void; addPendingStoryAdd: (generationId: string, storyId: string) => void; removePendingStoryAdd: (generationId: string) => string | undefined; - /** Legacy setter for backward compat with useRestoreActiveTasks */ - setIsGenerating: (generating: boolean) => void; setActiveGenerationId: (id: string | null) => void; activeGenerationId: string | null; } @@ -56,6 +54,5 @@ export const useGenerationStore = create((set, get) => ({ return storyId; }, - setIsGenerating: (generating) => set({ isGenerating: generating }), setActiveGenerationId: (id) => set({ activeGenerationId: id }), }));