diff --git a/src/composables/useApiRequest.test.ts b/src/composables/useApiRequest.test.ts index 04ad2c916f..9bccd7d313 100644 --- a/src/composables/useApiRequest.test.ts +++ b/src/composables/useApiRequest.test.ts @@ -38,6 +38,29 @@ describe('useApiRequest', () => { expect(error.value).toBeNull() }) + it('stays loading until every concurrent request settles', async () => { + const { isLoading, executeRequest } = useApiRequest({ + client, + mapError: vi.fn() + }) + + let resolveFirst!: (value: AxiosResponse) => void + const first = executeRequest( + () => new Promise>((res) => (resolveFirst = res)), + { errorContext: 'ctx' } + ) + const second = executeRequest(async () => response('second'), { + errorContext: 'ctx' + }) + + await second + expect(isLoading.value).toBe(true) + + resolveFirst(response('first')) + await first + expect(isLoading.value).toBe(false) + }) + it('passes the injected client to the api call', async () => { const apiCall = vi.fn(async () => response(1)) const { executeRequest } = useApiRequest({ client, mapError: vi.fn() }) diff --git a/src/composables/useApiRequest.ts b/src/composables/useApiRequest.ts index 90e1655c2a..9351aa937b 100644 --- a/src/composables/useApiRequest.ts +++ b/src/composables/useApiRequest.ts @@ -1,5 +1,5 @@ import type { AxiosInstance, AxiosResponse } from 'axios' -import { ref } from 'vue' +import { computed, ref } from 'vue' import { isAbortError } from '@/utils/typeGuardUtil' @@ -33,7 +33,8 @@ export function useApiRequest({ client: AxiosInstance mapError: ApiErrorMapper }) { - const isLoading = ref(false) + const pendingCount = ref(0) + const isLoading = computed(() => pendingCount.value > 0) const error = ref(null) async function executeRequest( @@ -42,7 +43,7 @@ export function useApiRequest({ ): Promise { const { errorContext, routeSpecificErrors, onSuccess } = options - isLoading.value = true + pendingCount.value++ error.value = null try { @@ -55,7 +56,7 @@ export function useApiRequest({ error.value = mapError(err, errorContext, routeSpecificErrors) return null } finally { - isLoading.value = false + pendingCount.value-- } } diff --git a/src/stores/comfyRegistryStore.test.ts b/src/stores/comfyRegistryStore.test.ts index 6cd1f73d3a..af5153f5c3 100644 --- a/src/stores/comfyRegistryStore.test.ts +++ b/src/stores/comfyRegistryStore.test.ts @@ -1,7 +1,8 @@ import { createTestingPinia } from '@pinia/testing' import { setActivePinia } from 'pinia' import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' -import { ref } from 'vue' +import type { ComputedRef } from 'vue' +import { computed, ref } from 'vue' import { useComfyRegistryService } from '@/services/comfyRegistryService' import { useComfyRegistryStore } from '@/stores/comfyRegistryStore' @@ -69,7 +70,7 @@ const mockListResult: operations['listAllNodes']['responses'][200]['content']['a describe('useComfyRegistryStore', () => { let mockRegistryService: { - isLoading: ReturnType> + isLoading: ComputedRef error: ReturnType> listAllPacks: ReturnType getPackById: ReturnType @@ -87,7 +88,7 @@ describe('useComfyRegistryStore', () => { setActivePinia(createTestingPinia({ stubActions: false })) vi.clearAllMocks() mockRegistryService = { - isLoading: ref(false), + isLoading: computed(() => false), error: ref(null), listAllPacks: vi.fn().mockImplementation((params) => { // If node_id is provided, return specific nodes diff --git a/src/workbench/extensions/manager/composables/useConflictDetection.test.ts b/src/workbench/extensions/manager/composables/useConflictDetection.test.ts index fca5e7de69..2448998a91 100644 --- a/src/workbench/extensions/manager/composables/useConflictDetection.test.ts +++ b/src/workbench/extensions/manager/composables/useConflictDetection.test.ts @@ -120,7 +120,7 @@ describe('useConflictDetection', () => { const mockComfyManagerService = { getImportFailInfoBulk: vi.fn(), - isLoading: ref(false), + isLoading: computed(() => false), error: ref(null) } as Partial> as ReturnType< typeof useComfyManagerService @@ -128,7 +128,7 @@ describe('useConflictDetection', () => { const mockRegistryService = { getBulkNodeVersions: vi.fn(), - isLoading: ref(false), + isLoading: computed(() => false), error: ref(null) } as Partial> as ReturnType< typeof useComfyRegistryService diff --git a/src/workbench/extensions/manager/stores/comfyManagerStore.test.ts b/src/workbench/extensions/manager/stores/comfyManagerStore.test.ts index fc8e00d549..6ac10d3658 100644 --- a/src/workbench/extensions/manager/stores/comfyManagerStore.test.ts +++ b/src/workbench/extensions/manager/stores/comfyManagerStore.test.ts @@ -1,7 +1,7 @@ import { createTestingPinia } from '@pinia/testing' import { setActivePinia } from 'pinia' import { beforeEach, describe, expect, it, vi } from 'vitest' -import { nextTick, ref } from 'vue' +import { computed, nextTick, ref } from 'vue' import { useComfyManagerService } from '@/workbench/extensions/manager/services/comfyManagerService' import { useComfyManagerStore } from '@/workbench/extensions/manager/stores/comfyManagerStore' @@ -80,7 +80,7 @@ describe('useComfyManagerStore', () => { setActivePinia(createTestingPinia({ stubActions: false })) vi.clearAllMocks() mockManagerService = { - isLoading: ref(false), + isLoading: computed(() => false), error: ref(null), startQueue: vi.fn().mockResolvedValue(null), getQueueStatus: vi.fn().mockResolvedValue(null),