Browse Source

refactor(gui-v2): replace `useUser` with global state

# What's changed?

* instead of using the useUser composable, we inject a global state containing user and token
pull/2716/head
Braks 2 years ago committed by Pranav C
parent
commit
0c36e8f16f
  1. 8
      packages/nc-gui-v2/components/smartsheet/Grid.vue
  2. 8
      packages/nc-gui-v2/composables/metas.ts
  3. 3
      packages/nc-gui-v2/composables/useGlobalState.ts
  4. 16
      packages/nc-gui-v2/composables/user.ts
  5. 3
      packages/nc-gui-v2/nuxt-shim.d.ts
  6. 29
      packages/nc-gui-v2/pages/signin.vue
  7. 27
      packages/nc-gui-v2/pages/signup.vue
  8. 47
      packages/nc-gui-v2/plugins/api.ts
  9. 9
      packages/nc-gui-v2/plugins/state.ts
  10. 5
      packages/nc-gui-v2/plugins/tele.ts

8
packages/nc-gui-v2/components/smartsheet/Grid.vue

@ -1,6 +1,5 @@
<script lang="ts" setup>
import { useNuxtApp } from '#app'
import { useUser } from '~/composables/user'
interface Props {
tabMeta: Record<string, any>
@ -10,20 +9,19 @@ interface Props {
const { tabMeta, meta } = defineProps<Props>()
const { project } = useProject()
const { user } = useUser()
const rows = ref()
const { $api } = useNuxtApp()
const { $api, $state } = useNuxtApp()
const loadData = async () => {
const response = await $api.dbTableRow.list(
'noco',
project.value.id,
project.value.id!,
meta.id,
{},
{
headers: {
'xc-auth': user.token,
'xc-auth': $state.value.token,
},
},
)

8
packages/nc-gui-v2/composables/metas.ts

@ -1,11 +1,9 @@
import type { TableType } from 'nocodb-sdk'
import { useNuxtApp, useState } from '#app'
import { useUser } from '~/composables/user'
import { useProject } from '~/composables/project'
export const useMetas = () => {
const { $api } = useNuxtApp()
const { user } = useUser()
const { tables } = useProject()
const metas = useState<{ [idOrTitle: string]: TableType | any }>('metas', () => ({}))
@ -19,11 +17,7 @@ export const useMetas = () => {
return
}
const model = await $api.dbTable.read(modelId, {
headers: {
'xc-auth': user.token,
},
})
const model = await $api.dbTable.read(modelId)
metas.value = {
...metas.value,

3
packages/nc-gui-v2/composables/useGlobalState.ts

@ -3,6 +3,9 @@ import type { GlobalState } from '~/lib/types'
const storageKey = 'nocodb-gui-v2'
/**
* Global State is injected by state plugin, so manual initialization is unnecessary and should be avoided
*/
export const useGlobalState = () => {
const preferredLanguages = $(usePreferredLanguages())
return createGlobalState(() =>

16
packages/nc-gui-v2/composables/user.ts

@ -1,16 +0,0 @@
import type { Api } from 'nocodb-sdk'
import { useNuxtApp } from '#app'
export const useUser = () => {
const { $api, $state } = useNuxtApp()
const getUser = async (...args: Parameters<Api<any>['auth']['me']>) => {
$state.user = await $api.auth.me(...args)
}
const setToken = (token?: string) => {
$state.token = token
}
return { user: $state.user, setToken, getUser }
}

3
packages/nc-gui-v2/nuxt-shim.d.ts vendored

@ -1,5 +1,6 @@
import type { NuxtApp as BaseApp } from '#app/nuxt'
import type { Api } from 'nocodb-sdk'
import type { RemovableRef } from '@vueuse/core'
import type { GlobalState } from '~/lib/types'
declare module '#app/nuxt' {
@ -10,6 +11,6 @@ declare module '#app/nuxt' {
}
// tele.emit
$e: (event: string, data: any) => void
$state: GlobalState
$state: RemovableRef<GlobalState>
}
}

29
packages/nc-gui-v2/pages/signin.vue

@ -1,27 +1,22 @@
<script setup lang="ts">
import { reactive, ref } from 'vue'
import { useUser } from '~/composables/user'
import { extractSdkResponseErrorMsg } from '~/helpers/errorUtils'
import { useNuxtApp, useRouter } from '#app'
import { navigateTo, useNuxtApp } from '#app'
const { $api } = useNuxtApp()
const $router = useRouter()
const { $api, $state } = useNuxtApp()
const valid = ref()
const error = ref()
const form = reactive({
email: '',
password: '',
})
const { user, setToken } = useUser()
const signIn = async () => {
error.value = null
try {
const { token } = await $api.auth.signin(form)
await setToken(token)
await $router.push('/projects')
} catch (e) {
$state.value.token = token
await navigateTo('/projects')
} catch (e: any) {
error.value = await extractSdkResponseErrorMsg(e)
}
}
@ -37,22 +32,26 @@ const signIn = async () => {
</v-alert>
<div class="p-float-label">
<v-text-field id="email" v-model="form.email" label="Email" type="text" style="width: 100%" />
<v-text-field id="email" v-model="form.email" :label="$t('labels.email')" type="text" style="width: 100%" />
</div>
<!-- Enter your password -->
<div class="p-float-label">
<v-text-field id="password" v-model="form.password" label="Password" type="password" style="width: 100%" />
<v-text-field
id="password"
v-model="form.password"
:label="$t('labels.password')"
type="password"
style="width: 100%"
/>
</div>
<div class="text-center">
<v-btn class="" @click="signIn">
<b>Sign In</b>
<b>{{ $t('general.signIn') }}</b>
</v-btn>
</div>
</v-card-text>
</v-card>
</div>
</template>
<style scoped></style>

27
packages/nc-gui-v2/pages/signup.vue

@ -1,24 +1,21 @@
<script setup lang="ts">
import { reactive, ref } from 'vue'
import { useUser } from '~/composables/user'
import { extractSdkResponseErrorMsg } from '~/helpers/errorUtils'
import { navigateTo } from '#app'
const { $api, $state } = useNuxtApp()
const { $api, $router } = useNuxtApp()
const valid = ref()
const error = ref()
const form = reactive({
email: '',
password: '',
})
const { user, setToken } = useUser()
const signUp = async () => {
error.value = null
try {
const { token } = await $api.auth.signup(form)
await setToken(token)
$router.push('/projects')
} catch (e) {
$state.value.token = token
navigateTo('/projects')
} catch (e: any) {
error.value = await extractSdkResponseErrorMsg(e)
}
}
@ -34,17 +31,23 @@ const signUp = async () => {
</v-alert>
<div class="p-float-label">
<v-text-field id="email" v-model="form.email" label="Email" type="text" style="width: 100%" />
<v-text-field id="email" v-model="form.email" :label="$t('labels.email')" type="text" style="width: 100%" />
</div>
<!-- Enter your password -->
<div class="p-float-label">
<v-text-field id="password" v-model="form.password" label="Password" type="password" style="width: 100%" />
<v-text-field
id="password"
v-model="form.password"
:label="$t('labels.password')"
type="password"
style="width: 100%"
/>
</div>
<div class="text-center">
<v-btn class="" @click="signUp">
<b>Sign Up</b>
<b>{{ $t('general.signUp') }}</b>
</v-btn>
</div>
</v-card-text>

47
packages/nc-gui-v2/plugins/api.ts

@ -2,24 +2,25 @@ import { Api } from 'nocodb-sdk'
import { defineNuxtPlugin } from 'nuxt3/app'
export default defineNuxtPlugin((nuxtApp) => {
const api = getApi(null, null)
const api = new Api({
baseURL: 'http://localhost:8080',
})
addAxiosInterceptors(api)
addAxiosInterceptors(api, nuxtApp)
nuxtApp.provide('api', api)
})
const DbNotFoundMsg = 'Database config not found'
function addAxiosInterceptors(api: Api<any>) {
function addAxiosInterceptors(api: Api<any>, app: any) {
const router = useRouter()
const route = useRoute()
const { user, setToken } = useUser()
api.instance.interceptors.request.use((config) => {
config.headers['xc-gui'] = 'true'
if (user?.token) config.headers['xc-auth'] = user?.token
if (app.$state.value.token) config.headers['xc-auth'] = app.$state.value.token
if (!config.url?.endsWith('/user/me') && !config.url?.endsWith('/admin/roles')) {
// config.headers['xc-preview'] = store.state.users.previewAs
@ -48,8 +49,7 @@ function addAxiosInterceptors(api: Api<any>) {
// Logout user if token refresh didn't work or user is disabled
if (error.config.url === '/auth/refresh-token') {
// todo: clear token
setToken()
app.$state.value.token = undefined
return new Promise((resolve, reject) => {
reject(error)
@ -65,7 +65,7 @@ function addAxiosInterceptors(api: Api<any>) {
// New request with new token
const config = error.config
config.headers['xc-auth'] = token.data.token
if (user) user.token = token.data.token
if (app.$state.value.token) app.$state.value.token = token.data.token
return new Promise((resolve, reject) => {
api.instance
@ -79,38 +79,13 @@ function addAxiosInterceptors(api: Api<any>) {
})
})
.catch(async (error) => {
// todo: clear token
// await store.dispatch('users/ActSignOut')
setToken()
app.$state.value.token = undefined
// todo: handle new user
// if (store.state.project.appInfo.firstUser) {
// router.replace('/')
// }
// else {
// $toast.clear()
// $toast.info('Token Expired. Please login again.', {
// position: 'bottom-center'
// }).goAway(5000)
router.replace('/signin')
// }
return Promise.reject(error)
})
},
)
}
export function getApi(store: any, axios: any) {
const api = new Api({
baseURL: 'http://localhost:8080',
headers: {
'xc-auth': store?.state?.users?.token,
},
})
if (axios) {
// overwrite with nuxt axios instance
api.instance = axios
}
return api
}

9
packages/nc-gui-v2/plugins/state.ts

@ -1,7 +1,12 @@
import { defineNuxtPlugin } from '#app'
import { defineNuxtPlugin } from 'nuxt3/app'
import { useGlobalState } from '~/composables/useGlobalState'
export default defineNuxtPlugin((nuxtApp) => {
const createGlobalState = useGlobalState()
nuxtApp.provide('state', createGlobalState())
const globalState = createGlobalState()
// set initial app language to the first preferred language (found in state)
;(nuxtApp.vueApp as any).i18n.global.locale.value = globalState.value.lang
nuxtApp.provide('state', globalState)
})

5
packages/nc-gui-v2/plugins/tele.ts

@ -6,7 +6,6 @@ import io from 'socket.io-client'
export default defineNuxtPlugin(async (nuxtApp) => {
const router = useRouter()
const route = useRoute()
const { user } = useUser()
let socket: Socket
@ -77,10 +76,10 @@ export default defineNuxtPlugin(async (nuxtApp) => {
}
}
if (user?.token) await init(user.token)
if (nuxtApp.$state.user && nuxtApp.$state.token) await init(nuxtApp.$state.token)
watch(
() => user?.token,
() => nuxtApp.$state.token,
(newToken, oldToken) => {
if (newToken !== oldToken) init(newToken)
else if (!newToken) socket.disconnect()

Loading…
Cancel
Save