diff --git a/src/stores/executionStore.test.ts b/src/stores/executionStore.test.ts index 3850a161b9..6cc2749ad0 100644 --- a/src/stores/executionStore.test.ts +++ b/src/stores/executionStore.test.ts @@ -132,6 +132,48 @@ describe('useExecutionStore - NodeLocatorId conversions', () => { }) }) +describe('useExecutionStore - reconcileInitializingPrompts', () => { + let store: ReturnType + + beforeEach(() => { + vi.clearAllMocks() + setActivePinia(createTestingPinia({ stubActions: false })) + store = useExecutionStore() + }) + + it('should remove prompt IDs not present in active jobs', () => { + store.initializingPromptIds = new Set(['job-1', 'job-2', 'job-3']) + + store.reconcileInitializingPrompts(new Set(['job-1'])) + + expect(store.initializingPromptIds).toEqual(new Set(['job-1'])) + }) + + it('should be a no-op when all initializing IDs are active', () => { + store.initializingPromptIds = new Set(['job-1', 'job-2']) + + store.reconcileInitializingPrompts(new Set(['job-1', 'job-2', 'job-3'])) + + expect(store.initializingPromptIds).toEqual(new Set(['job-1', 'job-2'])) + }) + + it('should be a no-op when there are no initializing prompts', () => { + store.initializingPromptIds = new Set() + + store.reconcileInitializingPrompts(new Set(['job-1'])) + + expect(store.initializingPromptIds).toEqual(new Set()) + }) + + it('should clear all initializing IDs when no active jobs exist', () => { + store.initializingPromptIds = new Set(['job-1', 'job-2']) + + store.reconcileInitializingPrompts(new Set()) + + expect(store.initializingPromptIds).toEqual(new Set()) + }) +}) + describe('useExecutionStore - Node Error Lookups', () => { let store: ReturnType diff --git a/src/stores/executionStore.ts b/src/stores/executionStore.ts index ecd75ffae0..35f0fed0df 100644 --- a/src/stores/executionStore.ts +++ b/src/stores/executionStore.ts @@ -442,6 +442,13 @@ export const useExecutionStore = defineStore('execution', () => { initializingPromptIds.value = next } + function reconcileInitializingPrompts(activeJobIds: Set) { + const orphaned = [...initializingPromptIds.value].filter( + (id) => !activeJobIds.has(id) + ) + clearInitializationByPromptIds(orphaned) + } + function isPromptInitializing( promptId: string | number | undefined ): boolean { @@ -716,6 +723,7 @@ export const useExecutionStore = defineStore('execution', () => { isPromptInitializing, clearInitializationByPromptId, clearInitializationByPromptIds, + reconcileInitializingPrompts, bindExecutionEvents, unbindExecutionEvents, storePrompt, diff --git a/src/stores/queueStore.ts b/src/stores/queueStore.ts index fd4a77886a..07ffd9060a 100644 --- a/src/stores/queueStore.ts +++ b/src/stores/queueStore.ts @@ -537,6 +537,18 @@ export const useQueueStore = defineStore('queue', () => { } }) + // Only reconcile when the queue fetch returned data. api.getQueue() + // returns empty Running/Pending on transient errors, which would + // incorrectly clear all initializing prompts. + const queueHasData = queue.Running.length > 0 || queue.Pending.length > 0 + if (queueHasData) { + const activeJobIds = new Set([ + ...queue.Running.map((j) => j.id), + ...queue.Pending.map((j) => j.id) + ]) + executionStore.reconcileInitializingPrompts(activeJobIds) + } + // Sort by create_time descending and limit to maxItems const sortedHistory = [...history] .sort((a, b) => b.create_time - a.create_time)