diff --git a/packages/nc-gui-v2/composables/useApi/index.ts b/packages/nc-gui-v2/composables/useApi/index.ts index 4e2df2fe90..e26767f419 100644 --- a/packages/nc-gui-v2/composables/useApi/index.ts +++ b/packages/nc-gui-v2/composables/useApi/index.ts @@ -3,7 +3,7 @@ import { Api } from 'nocodb-sdk' import type { Ref } from 'vue' import type { EventHook, MaybeRef } from '@vueuse/core' import { addAxiosInterceptors } from './interceptors' -import { createEventHook, ref, unref, useGlobal } from '#imports' +import { createEventHook, ref, unref, useCounter, useGlobal } from '#imports' interface UseApiReturn { api: Api @@ -52,30 +52,57 @@ interface UseApiProps { export function useApi(props: UseApiProps = {}): UseApiReturn { const state = useGlobal() + /** + * Local state of running requests, do not confuse with global state of running requests + * This state is only counting requests made by this instance of `useApi` and not by other instances. + */ + const { count, inc, dec } = useCounter(0) + + /** is request loading */ const isLoading = ref(false) + /** latest request error */ const error = ref(null) - const response = ref(null) + /** latest request response */ + const response = ref(null) const errorHook = createEventHook>() const responseHook = createEventHook>() + /** fresh api instance - with interceptors for token refresh already bound */ const api = createApiInstance(props.apiOptions) + /** increment local and global request counter */ function addRequest() { - state.runningRequests.value.push(state.runningRequests.value.length + 1) + inc() + state.runningRequests.inc() } + /** decrement local and global request counter */ function removeRequest() { - state.runningRequests.value.pop() + dec() + state.runningRequests.dec() + } + + /** set loading state to false *only* if no request is still running */ + function stopLoading() { + if (count.value === 0) { + isLoading.value = false + } + } + + /** reset response and error refs */ + function reset() { + error.value = null + response.value = null } api.instance.interceptors.request.use( (config) => { - error.value = null - response.value = null + reset() + isLoading.value = true addRequest() @@ -88,8 +115,10 @@ export function useApi(props: UseApiProps (requestError) => { errorHook.trigger(requestError) error.value = requestError + response.value = null - isLoading.value = false + + stopLoading() removeRequest() @@ -100,9 +129,9 @@ export function useApi(props: UseApiProps api.instance.interceptors.response.use( (apiResponse) => { responseHook.trigger(apiResponse as AxiosResponse) - // can't properly typecast response.value = apiResponse - isLoading.value = false + + stopLoading() removeRequest() @@ -111,7 +140,8 @@ export function useApi(props: UseApiProps (apiError) => { errorHook.trigger(apiError) error.value = apiError - isLoading.value = false + + stopLoading() removeRequest() @@ -119,5 +149,12 @@ export function useApi(props: UseApiProps }, ) - return { api, isLoading, response, error, onError: errorHook.on, onResponse: responseHook.on } + return { + api, + isLoading, + response: response as Ref>, + error, + onError: errorHook.on, + onResponse: responseHook.on, + } } diff --git a/packages/nc-gui-v2/composables/useGlobal/getters.ts b/packages/nc-gui-v2/composables/useGlobal/getters.ts index a9012bc923..61081a8ea2 100644 --- a/packages/nc-gui-v2/composables/useGlobal/getters.ts +++ b/packages/nc-gui-v2/composables/useGlobal/getters.ts @@ -17,7 +17,7 @@ export function useGlobalGetters(state: State): Getters { /** global loading state */ let loading = $ref(false) const isLoading = computed({ - get: () => state.runningRequests.value.length > 0 || loading, + get: () => state.runningRequests.count.value > 0 || loading, set: (_loading) => (loading = !_loading), }) diff --git a/packages/nc-gui-v2/composables/useGlobal/state.ts b/packages/nc-gui-v2/composables/useGlobal/state.ts index 92780a0325..8bb3266504 100644 --- a/packages/nc-gui-v2/composables/useGlobal/state.ts +++ b/packages/nc-gui-v2/composables/useGlobal/state.ts @@ -2,7 +2,7 @@ import { usePreferredLanguages, useStorage } from '@vueuse/core' import { useJwt } from '@vueuse/integrations/useJwt' import type { JwtPayload } from 'jwt-decode' import type { State, StoredState } from './types' -import { computed, ref, toRefs, useNuxtApp, useTimestamp } from '#imports' +import { computed, ref, toRefs, useCounter, useNuxtApp, useTimestamp } from '#imports' import type { User } from '~/lib' export function useGlobalState(storageKey = 'nocodb-gui-v2'): State { @@ -67,7 +67,7 @@ export function useGlobalState(storageKey = 'nocodb-gui-v2'): State { const sidebarOpen = ref(false) /** currently running requests */ - const runningRequests = ref([]) + const runningRequests = useCounter() /** global error */ const error = ref() diff --git a/packages/nc-gui-v2/composables/useGlobal/types.ts b/packages/nc-gui-v2/composables/useGlobal/types.ts index fd58de702a..c989476338 100644 --- a/packages/nc-gui-v2/composables/useGlobal/types.ts +++ b/packages/nc-gui-v2/composables/useGlobal/types.ts @@ -2,6 +2,7 @@ import type { ComputedRef, Ref, ToRefs } from 'vue' import type { WritableComputedRef } from '@vue/reactivity' import type { JwtPayload } from 'jwt-decode' import type { User } from '~/lib' +import type { useCounter } from '#imports' export interface StoredState { token: string | null @@ -16,7 +17,7 @@ export type State = ToRefs> & { jwtPayload: ComputedRef<(JwtPayload & User) | null> sidebarOpen: Ref timestamp: Ref - runningRequests: Ref + runningRequests: ReturnType error: Ref }