diff --git a/packages/nc-gui-v2/composables/useApi/index.ts b/packages/nc-gui-v2/composables/useApi/index.ts index 4bc0d158d3..9d27fd3280 100644 --- a/packages/nc-gui-v2/composables/useApi/index.ts +++ b/packages/nc-gui-v2/composables/useApi/index.ts @@ -3,8 +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, useNuxtApp } from '#imports' -import type { NuxtApp } from '#app' +import { createEventHook, ref, unref, useGlobal } from '#imports' interface UseApiReturn { api: Api @@ -15,23 +14,26 @@ interface UseApiReturn { onResponse: EventHook>['on'] } -export function createApiInstance(app: NuxtApp, baseURL = 'http://localhost:8080') { - const api = new Api({ - baseURL, - }) - - addAxiosInterceptors(api, app) +interface CreateApiOptions { + baseURL?: string +} - return api +export function createApiInstance(options: CreateApiOptions = {}): Api { + return addAxiosInterceptors( + new Api({ + baseURL: options.baseURL ?? 'http://localhost:8080', + }), + ) } -/** todo: add props? */ interface UseApiProps { axiosConfig?: MaybeRef> - useGlobalInstance?: MaybeRef + apiOptions?: CreateApiOptions } export function useApi(props: UseApiProps = {}): UseApiReturn { + const state = $(useGlobal()) + const isLoading = ref(false) const error = ref(null) @@ -42,7 +44,15 @@ export function useApi(props: UseApiProps const responseHook = createEventHook>() - const api = unref(props.useGlobalInstance) ? useNuxtApp().$api : createApiInstance(useNuxtApp()) + const api = createApiInstance(props.apiOptions) + + function addRequest() { + state.runningRequests.push(state.runningRequests.length + 1) + } + + function removeRequest() { + state.runningRequests.pop() + } api.instance.interceptors.request.use( (config) => { @@ -50,6 +60,8 @@ export function useApi(props: UseApiProps response.value = null isLoading.value = true + addRequest() + return { ...config, ...unref(props), @@ -61,6 +73,8 @@ export function useApi(props: UseApiProps response.value = null isLoading.value = false + removeRequest() + return requestError }, ) @@ -72,6 +86,8 @@ export function useApi(props: UseApiProps response.value = apiResponse isLoading.value = false + removeRequest() + return apiResponse }, (apiError) => { @@ -79,6 +95,8 @@ export function useApi(props: UseApiProps error.value = apiError isLoading.value = false + removeRequest() + return apiError }, ) diff --git a/packages/nc-gui-v2/composables/useApi/interceptors.ts b/packages/nc-gui-v2/composables/useApi/interceptors.ts index 9b655e836b..b483ca333c 100644 --- a/packages/nc-gui-v2/composables/useApi/interceptors.ts +++ b/packages/nc-gui-v2/composables/useApi/interceptors.ts @@ -1,17 +1,17 @@ import type { Api } from 'nocodb-sdk' -import { navigateTo, useRoute, useRouter } from '#imports' -import type { NuxtApp } from '#app' +import { navigateTo, useGlobal, useRoute, useRouter } from '#imports' const DbNotFoundMsg = 'Database config not found' -export function addAxiosInterceptors(api: Api, app: NuxtApp) { +export function addAxiosInterceptors(api: Api) { + const state = $(useGlobal()) const router = useRouter() const route = useRoute() api.instance.interceptors.request.use((config) => { config.headers['xc-gui'] = 'true' - if (app.$state.token.value) config.headers['xc-auth'] = app.$state.token.value + if (state.token) config.headers['xc-auth'] = state.token if (!config.url?.endsWith('/user/me') && !config.url?.endsWith('/admin/roles')) { // config.headers['xc-preview'] = store.state.users.previewAs @@ -38,7 +38,7 @@ export function addAxiosInterceptors(api: Api, app: NuxtApp) { // Logout user if token refresh didn't work or user is disabled if (error.config.url === '/auth/refresh-token') { - app.$state.signOut() + state.signOut() return Promise.reject(error) } @@ -52,7 +52,7 @@ export function addAxiosInterceptors(api: Api, app: NuxtApp) { // New request with new token const config = error.config config.headers['xc-auth'] = token.data.token - app.$state.signIn(token.data.token) + state.signIn(token.data.token) return new Promise((resolve, reject) => { api.instance @@ -66,7 +66,7 @@ export function addAxiosInterceptors(api: Api, app: NuxtApp) { }) }) .catch(async (error) => { - app.$state.signOut() + state.signOut() // todo: handle new user navigateTo('/signIn') @@ -75,4 +75,6 @@ export function addAxiosInterceptors(api: Api, app: NuxtApp) { }) }, ) + + return api } diff --git a/packages/nc-gui-v2/composables/useGlobal/getters.ts b/packages/nc-gui-v2/composables/useGlobal/getters.ts index fcccaa775f..0d7c51728d 100644 --- a/packages/nc-gui-v2/composables/useGlobal/getters.ts +++ b/packages/nc-gui-v2/composables/useGlobal/getters.ts @@ -1,8 +1,7 @@ import type { Getters, State } from './types' import { computed } from '#imports' -export function useGlobalGetters(state: State) { - /** Getters */ +export function useGlobalGetters(state: State): Getters { /** Verify that a user is signed in by checking if token exists and is not expired */ const signedIn: Getters['signedIn'] = computed( () => @@ -15,5 +14,12 @@ export function useGlobalGetters(state: State) { ), ) - return { signedIn } + /** global loading state */ + let loading = $ref(false) + const isLoading = computed({ + get: () => state.runningRequests.value.length > 0 || loading, + set: (_loading) => (loading = _loading), + }) + + return { signedIn, isLoading } } diff --git a/packages/nc-gui-v2/composables/useGlobal/state.ts b/packages/nc-gui-v2/composables/useGlobal/state.ts index 922ee18b2b..c0dad1848e 100644 --- a/packages/nc-gui-v2/composables/useGlobal/state.ts +++ b/packages/nc-gui-v2/composables/useGlobal/state.ts @@ -68,9 +68,6 @@ export function useGlobalState(): State { /** is sidebar open */ const sidebarOpen = ref(false) - /** global loading state */ - const isLoading = ref(false) - /** currently running requests */ const runningRequests = ref([]) @@ -83,7 +80,6 @@ export function useGlobalState(): State { jwtPayload: payload, sidebarOpen, timestamp, - isLoading, runningRequests, error, } diff --git a/packages/nc-gui-v2/composables/useGlobal/types.ts b/packages/nc-gui-v2/composables/useGlobal/types.ts index a4b833696c..009c2369bf 100644 --- a/packages/nc-gui-v2/composables/useGlobal/types.ts +++ b/packages/nc-gui-v2/composables/useGlobal/types.ts @@ -11,17 +11,17 @@ export interface StoredState { } export type State = ToRefs> & { - token: WritableComputedRef + token: WritableComputedRef jwtPayload: ComputedRef<(JwtPayload & User) | null> sidebarOpen: Ref timestamp: Ref - isLoading: Ref runningRequests: Ref error: Ref } export interface Getters { signedIn: ComputedRef + isLoading: WritableComputedRef } export interface Actions { diff --git a/packages/nc-gui-v2/plugins/api.ts b/packages/nc-gui-v2/plugins/api.ts index 26acda6841..0e868b2a64 100644 --- a/packages/nc-gui-v2/plugins/api.ts +++ b/packages/nc-gui-v2/plugins/api.ts @@ -1,7 +1,6 @@ -import { defineNuxtPlugin } from '#imports' -import { createApiInstance } from '~/composables/useApi' +import { defineNuxtPlugin, useApi } from '#imports' export default defineNuxtPlugin((nuxtApp) => { /** injects a global api instance */ - nuxtApp.provide('api', createApiInstance(nuxtApp)) + nuxtApp.provide('api', useApi().api) })