Browse Source

wip: basic tab, project and user state added

Signed-off-by: Pranav C <pranavxc@gmail.com>
pull/2524/head
Pranav C 2 years ago
parent
commit
ffbc8ab291
  1. 31
      packages/nc-gui-v2/components/dashboard/TabView.vue
  2. 22
      packages/nc-gui-v2/components/dashboard/TreeView.vue
  3. 56
      packages/nc-gui-v2/components/smartsheet/Grid.vue
  4. 36
      packages/nc-gui-v2/components/tabs/Smartsheet.vue
  5. 41
      packages/nc-gui-v2/composables/metas.ts
  6. 36
      packages/nc-gui-v2/composables/project.ts
  7. 17
      packages/nc-gui-v2/composables/tabs.ts
  8. 20
      packages/nc-gui-v2/composables/user.ts
  9. 14
      packages/nc-gui-v2/helpers/errorUtils.ts
  10. 14
      packages/nc-gui-v2/layouts/default.vue
  11. 3
      packages/nc-gui-v2/nuxt.config.ts
  12. 56
      packages/nc-gui-v2/pages/dashboard/[projectId].vue
  13. 51
      packages/nc-gui-v2/pages/projects/index.vue
  14. 0
      packages/nc-gui-v2/pages/sample.vue
  15. 92
      packages/nc-gui-v2/pages/signin.vue
  16. 57
      packages/nc-gui-v2/pages/signup.vue
  17. 8
      packages/nc-gui-v2/plugins/primevue.ts
  18. 3
      packages/nc-gui-v2/tsconfig.json

31
packages/nc-gui-v2/components/dashboard/TabView.vue

@ -0,0 +1,31 @@
<template>
<div>
<TabMenu :model="tabItems" v-model:activeIndex="activeIndex"/>
<template v-if="tabItems && tabItems[activeIndex]">
<TabsSmartsheet :tab-meta="tabs[activeIndex]" :key="tabs[activeIndex].id"/>
</template>
</div>
</template>
<script setup lang="ts">
import {useTabs} from "~/composables/tabs";
const {tabs} = useTabs()
const activeIndex = ref(0)
const tabItems = computed(() => {
return tabs.value.map(tab => {
return {
label: tab.title,
// icon: tab.icon,
closable: true
}
})
})
</script>
<style scoped>
</style>

22
packages/nc-gui-v2/components/dashboard/TreeView.vue

@ -0,0 +1,22 @@
<template>
<div>
<div v-for="table in tables" class="p-2 text-sm"
@click="addTab({type:'table',title:table.title, id:table.id})">
{{ table.title }}
</div>
</div>
</template>
<script setup lang="ts">
import {useProject} from "~/composables/project";
import {useTabs} from "~/composables/tabs";
const {tables} = useProject()
const {addTab} = useTabs()
</script>
<style scoped>
</style>

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

@ -0,0 +1,56 @@
<template>
<div>
<div class="card">
<DataTable :value="rows" responsiveLayout="scroll">
<Column v-for="col in meta.columns" :key="col.id" :field="col.title" :header="col.title">
<template v-if="col.uidt === 'LinkToAnotherRecord'" #body="{data:{[col.title]:d}}">
{{ d&& (Array.isArray(d) ? d : [d]).map(c1 => c1[Object.keys(c1)[1]]).join(', ') }}
</template>
</Column>
</DataTable>
</div>
</div>
</template>
<script lang="ts" setup>
import {useNuxtApp} from "#app";
import {Api} from "nocodb-sdk";
import {useUser} from "~/composables/user";
const {tabMeta, meta} = defineProps({
tabMeta: Object,
meta: Object
})
const {project} = useProject()
const {user} = useUser()
const rows = ref()
const {$api}: { $api: Api<any> } = useNuxtApp() as any
const loadData = async () => {
const response = await $api.dbTableRow.list('noco',
project.value.id,
meta.id, {}, {
headers: {
'xc-auth': user.token
}
})
rows.value = response.list
}
onMounted(async () => {
await loadData()
})
</script>
<style scoped>
</style>

36
packages/nc-gui-v2/components/tabs/Smartsheet.vue

@ -0,0 +1,36 @@
<template>
<div>
<template v-if="meta && tabMeta">
<SmartsheetGrid :meta="meta" :tabMeta="tabMeta"></SmartsheetGrid>
</template>
</div>
</template>
<script setup lang="ts">
import {useMetas} from "~/composables/metas";
import {computed, onMounted, watch} from 'vue'
const {tabMeta} = defineProps({
tabMeta: Object
})
const {getMeta, metas} = useMetas()
const meta = computed(() => {
return metas.value?.[tabMeta?.id]
})
onMounted(async () => {
await getMeta(tabMeta?.id)
})
watch(() => tabMeta && tabMeta?.id, async (newVal, oldVal) => {
if (newVal !== oldVal) {
await getMeta(newVal)
}
})
</script>
<style scoped>
</style>

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

@ -0,0 +1,41 @@
import {useNuxtApp, useState} from "#app";
import {Api, TableType} from "nocodb-sdk";
import {useUser} from "~/composables/user";
import {useProject} from "~/composables/project";
export const useMetas = () => {
const {$api}: { $api: Api<any> } = useNuxtApp() as any
const {user} = useUser()
const {tables} = useProject()
const metas = useState<{ [idOrTitle: string]: TableType | any }>('metas', () => ({}))
const getMeta = async (tableIdOrTitle: string, force = false) => {
if (!force && metas[tableIdOrTitle]) {
return metas[tableIdOrTitle]
}
const modelId = (tables.value.find(t => t.title === tableIdOrTitle || t.id === tableIdOrTitle) || {}).id
if (!modelId) {
console.warn(`Table '${tableIdOrTitle}' is not found in the table list`)
return
}
const model = await $api.dbTable.read(modelId, {
headers: {
'xc-auth': user.token
}
})
metas.value = {
...metas.value,
[model.id]: model,
[model.title]: model
}
return model
}
return {getMeta, metas}
}

36
packages/nc-gui-v2/composables/project.ts

@ -0,0 +1,36 @@
import {useNuxtApp} from "#app";
import {Api, TableType} from "nocodb-sdk";
import {useUser} from "~/composables/user";
export const useProject = () => {
const {$api}: { $api: Api<any> } = useNuxtApp() as any
const {user} = useUser()
const project = useState<{ id?: string, title?: string }>('project', null)
const tables = useState<Array<TableType>>('tables', null)
const loadTables = async () => {
const tablesResponse = await $api.dbTable.list(project?.value?.id, {}, {
headers: {
'xc-auth': user.token
}
})
console.log(tablesResponse)
tables.value = tablesResponse.list
}
const loadProject = async (projectId:string) => {
const projectResponse = await $api.project.read(projectId, {
headers: {
'xc-auth': user.token
}
})
console.log(projectResponse)
project.value = projectResponse
}
return {project, tables, loadProject, loadTables}
}

17
packages/nc-gui-v2/composables/tabs.ts

@ -0,0 +1,17 @@
import {useState} from "#app";
interface TabItem {
type: 'table' | 'view',
title: string,
id:string
}
export const useTabs = () => {
const tabs = useState<Array<TabItem>>('tabs', () => [])
const addTab = (tabMeta: TabItem) => {
tabs.value = [...(tabs.value || []), tabMeta]
}
return {tabs, addTab}
}

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

@ -1,9 +1,15 @@
import {store} from 'nuxt3-store'
export const user = store({
name: 'user',
type: 'localstorage',
value: {token: null},
reactiveType: 'reactive',
version: '1.0.0'
})
export const useUser = () =>{
const user = store({
name: 'user',
type: 'localstorage',
value: {token: null},
reactiveType: 'reactive',
version: '1.0.0'
})
const setToken = (token) => { user.token = token }
return {user,setToken}
}

14
packages/nc-gui-v2/helpers/errorUtils.ts

@ -0,0 +1,14 @@
export async function extractSdkResponseErrorMsg(e:Error & {response:any}) {
if (!e || !e.response) { return e.message }
let msg
if (e.response.data instanceof Blob) {
try {
msg = JSON.parse(await e.response.data.text()).msg
} catch {
msg = 'Some internal error occurred'
}
} else {
msg = e.response.data.msg || 'Some internal error occurred'
}
return msg || 'Some error occurred'
}

14
packages/nc-gui-v2/layouts/default.vue

@ -1,11 +1,13 @@
<template>
<v-layout>
<v-app-bar color="grey-lighten-2"></v-app-bar>
<!-- <v-navigation-drawer color="grey-darken-2" permanent></v-navigation-drawer>-->
<v-main>
<div class="">
<div class="topbar">
</div>
<div class="sidebar">
</div>
<div class="content">
<slot></slot>
</v-main>
</v-layout>
</div>
</div>
</template>
<script>

3
packages/nc-gui-v2/nuxt.config.ts

@ -20,7 +20,8 @@ export default defineNuxtConfig({
css: [
'primevue/resources/themes/saga-blue/theme.css',
'primevue/resources/primevue.css',
'primeicons/primeicons.css'
'primeicons/primeicons.css',
'primeflex/primeflex.css',
],
build: {
transpile: ['primevue']

56
packages/nc-gui-v2/pages/dashboard/[projectId].vue

@ -0,0 +1,56 @@
<template>
<div class="nc-container">
<div class="nc-topbar shadow-2">
</div>
<div class="nc-sidebar shadow-2 p-4 overflow-y-auto">
<DashboardTreeView></DashboardTreeView>
</div>
<div class="nc-content p-4 overflow-auto">
<DashboardTabView></DashboardTabView>
</div>
</div>
</template>
<script setup lang="ts">
import {useNuxtApp} from "#app";
import {useProject} from "~/composables/project";
const route = useRoute()
const {loadProject, loadTables} = useProject()
onMounted(async () => {
await loadProject(route.params.projectId as string)
await loadTables()
})
</script>
<style scoped lang="scss">
.nc-container {
.nc-topbar {
position: fixed;
top: 0;
left: 0;
height: 50px;
width: 100%;
}
.nc-sidebar {
position: fixed;
top: 50px;
left: 0;
height: calc(100% - 50px);
width: 250px;
}
.nc-content {
position: fixed;
top: 50px;
left: 250px;
height: calc(100% - 50px);
width: calc(100% - 250px);
}
}
</style>

51
packages/nc-gui-v2/pages/projects/index.vue

@ -0,0 +1,51 @@
<template>
<div>
<div class="grid">
<div class="col-3 p-3" v-for="project in projects" :key="project.id">
<Card @click="navigateToDashboard(project)">
<template #content>
<div class="text-center">
<h3>{{ project.title }}</h3>
</div>
</template>
</Card>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import {Api} from "nocodb-sdk";
const {$api, $router}= useNuxtApp()
const projects = ref()
const {user} = useUser()
const loadProjects = async () => {
const projectsResponse = await $api.project.list({}, {
headers: {
'xc-auth': user.token
}
})
projects.value = projectsResponse.list
}
const navigateToDashboard = async (project) => {
await $router.push({
path: '/dashboard/' + project.id
})
}
onMounted(async () => {
await loadProjects()
})
</script>
<style scoped>
</style>

0
packages/nc-gui-v2/pages/dashboard.vue → packages/nc-gui-v2/pages/sample.vue

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

@ -1,72 +1,62 @@
<template>
<v-cotainer>
<v-card max-width="500" class="pa-4 mx-auto mt-10">
{{userStore}}
<v-form
ref="formType"
v-model="valid"
lazy-validation
>
<!-- Enter your work email -->
<v-text-field
v-model="form.email"
label="Email"
required
/>
<div>
<!-- Enter your work email -->
<Card class="p-4 mx-auto mt-5" style="max-width: 500px">
<template #content>
<!-- Enter your password -->
<v-text-field
label="Password"
v-model="form.password"
name="input-10-2"
min="8"
/>
<Message class="" v-if="error" severity="error">{{ error }}</Message>
<v-btn
class="mx-auto"
large
elevation-10
:disabled="false"
@click="signIn"
>
<b>Sign In</b>
</v-btn>
<div class="p-float-label mt-5">
<InputText id="email" type="text" v-model="form.email" style="width:100%"/>
<label for="email">Email</label>
</div>
</v-form>
</v-card>
</v-cotainer>
<!-- Enter your password -->
<div class="p-float-label mt-5">
<InputText id="password" type="password" v-model="form.password" style="width:100%"/>
<label for="password">Password</label>
</div>
<div class="text-center">
<Button
class="mt-5"
@click="signIn"
>
<b>Sign In</b>
</Button>
</div>
</template>
</Card>
</div>
</template>
<script setup lang="ts">
import {ref, reactive} from 'vue'
import {useUser} from "~/composables/user";
import {extractSdkResponseErrorMsg} from "~/helpers/errorUtils";
import {useNuxtApp} from "#app";
const {$api} = useNuxtApp()
const valid = ref()
const error = ref()
const form = reactive({
email: '',
password: ''
})
const userStore = user
</script>
<script lang="ts">
import {useNuxtApp} from "nuxt/app";
import {Api} from "nocodb-sdk";
// const {$api}: { $api: Api<any> } = useNuxtApp() as any
export default {
methods: {
signIn() {
this.$api.auth.signin(this.form).then((res) => {
console.log(res)
this.userStore.token = res
})
}
const {user, setToken} = useUser()
const signIn = async () => {
error.value = null
try {
const {token} = await $api.auth.signin(form)
setToken(token)
} catch (e) {
error.value = await extractSdkResponseErrorMsg(e)
}
}
</script>
</script>
<style scoped>
</style>

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

@ -1,13 +1,62 @@
<template>
<div>
<!-- Enter your work email -->
<Card class="p-4 mx-auto mt-5" style="max-width: 500px">
<template #content>
<Message class="" v-if="error" severity="error">{{ error }}</Message>
<div class="p-float-label mt-5">
<InputText id="email" type="text" v-model="form.email" style="width:100%"/>
<label for="email">Email</label>
</div>
<!-- Enter your password -->
<div class="p-float-label mt-5">
<InputText id="password" type="password" v-model="form.password" style="width:100%"/>
<label for="password">Password</label>
</div>
<div class="text-center">
<Button
class="mt-5"
@click="signUp"
>
<b>Sign Up</b>
</Button>
</div>
</template>
</Card>
</div>
</template>
<script>
export default {
name: "signup"
<script setup lang="ts">
import {ref, reactive} from 'vue'
import {useUser} from "~/composables/user";
import {Api} from "nocodb-sdk";
import {extractSdkResponseErrorMsg} from "~/helpers/errorUtils";
const {$api}: { $api: Api<any> } = useNuxtApp() as any
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)
setToken(token)
} catch (e) {
error.value = await extractSdkResponseErrorMsg(e)
}
}
</script>
</script>
<style scoped>
</style>

8
packages/nc-gui-v2/plugins/primevue.ts

@ -5,6 +5,10 @@ import InputText from "primevue/inputtext";
import Toast from "primevue/toast";
import Card from "primevue/card";
import Sidebar from "primevue/sidebar";
import Message from "primevue/message";
import TabMenu from "primevue/tabmenu";
import DataTable from "primevue/datatable";
import Column from "primevue/column";
import ToastService from 'primevue/toastservice';
export default defineNuxtPlugin((nuxtApp) => {
@ -15,5 +19,9 @@ export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.vueApp.component('Toast', Toast);
nuxtApp.vueApp.component('Card', Card);
nuxtApp.vueApp.component('Sidebar', Sidebar);
nuxtApp.vueApp.component('Message', Message);
nuxtApp.vueApp.component('TabMenu', TabMenu);
nuxtApp.vueApp.component('DataTable', DataTable);
nuxtApp.vueApp.component('Column', Column);
//other components that you need
});

3
packages/nc-gui-v2/tsconfig.json

@ -1,4 +1,5 @@
{
// https://v3.nuxtjs.org/concepts/typescript
"extends": "./.nuxt/tsconfig.json"
"extends": "./.nuxt/tsconfig.json",
}

Loading…
Cancel
Save