mirror of
https://github.com/jamiepine/voicebox.git
synced 2026-09-18 22:30:40 -07:00
fix SSE cleanup, filter add popover to completed only, derive isGenerating from pending set, handle not_found status
This commit is contained in:
@@ -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)),
|
||||
);
|
||||
|
||||
@@ -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<Map<string, EventSource>>(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,
|
||||
|
||||
@@ -15,7 +15,6 @@ const POLL_INTERVAL = 30000;
|
||||
*/
|
||||
export function useRestoreActiveTasks() {
|
||||
const [activeDownloads, setActiveDownloads] = useState<ActiveDownloadTask[]>([]);
|
||||
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
|
||||
|
||||
@@ -3,7 +3,7 @@ import { create } from 'zustand';
|
||||
interface GenerationState {
|
||||
/** IDs of generations currently in progress */
|
||||
pendingGenerationIds: Set<string>;
|
||||
/** 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<string, string>;
|
||||
@@ -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<GenerationState>((set, get) => ({
|
||||
return storyId;
|
||||
},
|
||||
|
||||
setIsGenerating: (generating) => set({ isGenerating: generating }),
|
||||
setActiveGenerationId: (id) => set({ activeGenerationId: id }),
|
||||
}));
|
||||
|
||||
Reference in New Issue
Block a user