Browse Source

Merge branch 'nuxt3' into develop

pull/2524/head
Pranav C 2 years ago
parent
commit
563d4d9bc8
  1. 8
      packages/nc-gui-v2/.gitignore
  2. 42
      packages/nc-gui-v2/README.md
  3. 6
      packages/nc-gui-v2/app.vue
  4. BIN
      packages/nc-gui-v2/assets/icon.png
  5. 30
      packages/nc-gui-v2/components/dashboard/TabView.vue
  6. 24
      packages/nc-gui-v2/components/dashboard/TreeView.vue
  7. 56
      packages/nc-gui-v2/components/smartsheet/Grid.vue
  8. 36
      packages/nc-gui-v2/components/tabs/Smartsheet.vue
  9. 41
      packages/nc-gui-v2/composables/metas.ts
  10. 36
      packages/nc-gui-v2/composables/project.ts
  11. 22
      packages/nc-gui-v2/composables/tabs.ts
  12. 32
      packages/nc-gui-v2/composables/user.ts
  13. 14
      packages/nc-gui-v2/helpers/errorUtils.ts
  14. 21
      packages/nc-gui-v2/layouts/default.vue
  15. 35
      packages/nc-gui-v2/nuxt.config.ts
  16. 16104
      packages/nc-gui-v2/package-lock.json
  17. 24
      packages/nc-gui-v2/package.json
  18. 67
      packages/nc-gui-v2/pages/dashboard/[projectId].vue
  19. 42
      packages/nc-gui-v2/pages/form.vue
  20. 17
      packages/nc-gui-v2/pages/index.vue
  21. 88
      packages/nc-gui-v2/pages/projects/index.vue
  22. 18
      packages/nc-gui-v2/pages/sample.vue
  23. 65
      packages/nc-gui-v2/pages/signin.vue
  24. 62
      packages/nc-gui-v2/pages/signup.vue
  25. 41
      packages/nc-gui-v2/plugins/api.ts
  26. 27
      packages/nc-gui-v2/plugins/primevue.ts
  27. 21
      packages/nc-gui-v2/plugins/vuetify.ts
  28. 8
      packages/nc-gui-v2/tailwind.config.js
  29. 5
      packages/nc-gui-v2/tsconfig.json

8
packages/nc-gui-v2/.gitignore vendored

@ -0,0 +1,8 @@
node_modules
*.log*
.nuxt
.nitro
.cache
.output
.env
dist

42
packages/nc-gui-v2/README.md

@ -0,0 +1,42 @@
# Nuxt 3 Minimal Starter
Look at the [nuxt 3 documentation](https://v3.nuxtjs.org) to learn more.
## Setup
Make sure to install the dependencies:
```bash
# yarn
yarn install
# npm
npm install
# pnpm
pnpm install --shamefully-hoist
```
## Development Server
Start the development server on http://localhost:3000
```bash
npm run dev
```
## Production
Build the application for production:
```bash
npm run build
```
Locally preview production build:
```bash
npm run preview
```
Checkout the [deployment documentation](https://v3.nuxtjs.org/guide/deploy/presets) for more information.

6
packages/nc-gui-v2/app.vue

@ -0,0 +1,6 @@
<template>
<!-- <NuxtLayout>-->
<!-- <NuxtPage />-->
<!-- </NuxtLayout>-->
<NuxtPage/>
</template>

BIN
packages/nc-gui-v2/assets/icon.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

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

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

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

@ -0,0 +1,24 @@
<template>
<div>
<div v-for="table in tables" class="p-2 text-sm pointer"
@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>
.pointer{
cursor: pointer;
}
</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}
}

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

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

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

@ -0,0 +1,32 @@
import {store} from 'nuxt3-store'
import {Api} from "nocodb-sdk";
import {useNuxtApp} from "#app";
export const useUser = () =>{
const user = store({
name: 'user',
type: 'localstorage',
value: {token: null, user : null},
reactiveType: 'reactive',
version: '1.0.0'
})
const {$api}: { $api: Api<any> } = useNuxtApp() as any
const getUser =async (args = {}) => {
const userInfo = await $api.auth.me(args, {
headers: {
'xc-auth': user.value.token
}
})
user.user = userInfo
}
const setToken = (token) => {
user.token = token
}
return {user,setToken, getUser}
}

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 || e.response.data.message || 'Some internal error occurred'
}
return msg || 'Some error occurred'
}

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

@ -0,0 +1,21 @@
<template>
<div class="">
<!-- <div class="topbar">-->
<!-- </div>-->
<!-- <div class="sidebar">-->
<!-- </div>-->
<!-- <div class="content">-->
<slot></slot>
<!-- </div>-->
</div>
</template>
<script>
export default {
name: "default"
}
</script>
<style scoped>
</style>

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

@ -0,0 +1,35 @@
import {defineNuxtConfig} from 'nuxt'
// https://v3.nuxtjs.org/api/configuration/nuxt.config
export default defineNuxtConfig({
// modules: ['@nuxtjs/tailwindcss'],
// buildModules: [
// 'nuxt-vite'
// ],
modules: ['nuxt3-store'],
ssr:false,
plugins: [
// '~/plugins/vuetify.ts',
// '~/plugins/api.ts',
],
// css: ['vuetify/lib/styles/main.sass'],
// build: {
// transpile: ['vuetify']
// },
css: [
'primevue/resources/themes/saga-blue/theme.css',
'primevue/resources/primevue.css',
'primeicons/primeicons.css',
'primeflex/primeflex.css',
],
build: {
transpile: ['primevue']
},
vite: {
define: {
'process.env.DEBUG': 'false',
}
}
})

16104
packages/nc-gui-v2/package-lock.json generated

File diff suppressed because it is too large Load Diff

24
packages/nc-gui-v2/package.json

@ -0,0 +1,24 @@
{
"private": true,
"scripts": {
"build": "nuxt build",
"dev": "nuxt dev",
"generate": "nuxt generate",
"preview": "nuxt preview"
},
"devDependencies": {
"@nuxtjs/tailwindcss": "^5.1.2",
"fibers": "^5.0.1",
"nuxt": "3.0.0-rc.3",
"sass": "^1.53.0",
"sass-loader": "^10.3.0"
},
"dependencies": {
"nocodb-sdk": "file:../nocodb-sdk",
"nuxt3-store": "^1.0.0",
"vuetify": "^3.0.0-alpha.12",
"primevue": "3.10.0",
"primeflex": "3.2.0",
"primeicons": "5.0.0"
}
}

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

@ -0,0 +1,67 @@
<template>
<!-- todo: move to layout or create a reusable component -->
<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 {useProject} from "~/composables/project";
import {watch} from "vue";
import {useTabs} from "~/composables/tabs";
const route = useRoute()
const {loadProject, loadTables} = useProject()
const {clearTabs} = useTabs()
onMounted(async () => {
await loadProject(route.params.projectId as string)
await loadTables()
})
watch(() => route.params.projectId, async (newVal, oldVal) => {
if (newVal && newVal !== oldVal) {
clearTabs()
await loadProject(newVal as string)
await loadTables()
}
})
</script>
<style scoped lang="scss">
.nc-container {
.nc-topbar {
position: fixed;
top: 0;
left: 0;
height: 50px;
width: 100%;
z-index: 5;
}
.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>

42
packages/nc-gui-v2/pages/form.vue

@ -0,0 +1,42 @@
<template>
<div class="container">
<Card style="width:500px">
<template #title>
Signup
</template>
<template #content>
<InputText type="text" v-model="value" label="Email"/>
</template>
<template #footer>
<Button label="Small" icon="pi pi-check" class="p-button-sm" />
</template>
</Card>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { useToast } from "primevue/usetoast";
const text = ref();
const toast = useToast();
const greet = () => {
toast.add({severity: 'info', summary: 'Hello ' + text.value});
}
</script>
<style lang="scss">
.container {
margin: 0 auto;
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
div {
display: flex;
flex-direction: column;
align-items: center;
margin-top: 1rem;
}
}
</style>

17
packages/nc-gui-v2/pages/index.vue

@ -0,0 +1,17 @@
<template>
<div class="container">
</div>
</template>
<script setup lang="ts">
import {useRouter} from "#app";
const $router = useRouter()
$router.replace('/projects')
</script>
<style lang="scss">
</style>

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

@ -0,0 +1,88 @@
<template>
<!-- todo: move to layout or create a reusable component -->
<div class="nc-container">
<div class="nc-topbar shadow-2">
</div>
<div class="nc-sidebar shadow-2 p-4 overflow-y-auto">
</div>
<div class="nc-content p-4 overflow-auto">
<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>
</div>
</template>
<script setup lang="ts">
import {useRouter} from "#app";
const {$api} = useNuxtApp()
const {user} = useUser()
const $router = useRouter()
const projects = ref()
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('/dashboard/' + project.id)
}
onMounted(async () => {
await loadProjects()
})
</script>
<style scoped lang="scss">
.nc-container {
.nc-topbar {
position: fixed;
top: 0;
left: 0;
height: 50px;
width: 100%;
z-index: 5;
}
.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>

18
packages/nc-gui-v2/pages/sample.vue

@ -0,0 +1,18 @@
<template>
<div>
<Sidebar :visible="true" position="left" :dismissable="false">
Content
</Sidebar>
</div>
</template>
<script>
export default {
name: "dashboard"
}
</script>
<style scoped>
</style>

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

@ -0,0 +1,65 @@
<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="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, useRouter} from "#app";
const { $api} = useNuxtApp()
const $router = useRouter()
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) {
error.value = await extractSdkResponseErrorMsg(e)
}
}
</script>
<style scoped>
</style>

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

@ -0,0 +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 setup lang="ts">
import {ref, reactive} from 'vue'
import {useUser} from "~/composables/user";
import {extractSdkResponseErrorMsg} from "~/helpers/errorUtils";
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) {
error.value = await extractSdkResponseErrorMsg(e)
}
}
</script>
<style scoped>
</style>

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

@ -0,0 +1,41 @@
import { Api } from 'nocodb-sdk';
import {defineNuxtPlugin} from "nuxt3/app";
export default defineNuxtPlugin((nuxtApp) => {
// Doing something with nuxtApp
const api = getApi(null, null)
nuxtApp.provide('api', api)
return {
provide: {
api123:api
}
}
})
export function getApi($store, $axios) {
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
}
//
// export default function({ store: $store, $axios, ...rest }, inject) {
// const api = getApi($store, $axios)
//
// inject('api', api)
// }

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

@ -0,0 +1,27 @@
import {defineNuxtPlugin} from "#app";
import PrimeVue from "primevue/config";
import Button from "primevue/button";
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) => {
nuxtApp.vueApp.use(PrimeVue, {ripple: true});
nuxtApp.vueApp.use(ToastService);
nuxtApp.vueApp.component('Button', Button);
nuxtApp.vueApp.component('InputText', InputText);
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
});

21
packages/nc-gui-v2/plugins/vuetify.ts

@ -0,0 +1,21 @@
import { createVuetify } from 'vuetify'
import {
VApp,
VAppBar,
VBtn
} from 'vuetify/components'
import {defineNuxtPlugin} from "nuxt/app";
// Import everything
// import * as components from 'vuetify/components'
export default defineNuxtPlugin((nuxtApp) => {
// const vuetify = createVuetify({
// components/*: {
// VApp,
// VAppBar,
// VBtn*/
// // }
// })
// nuxtApp.vueApp.use(vuetify)
})

8
packages/nc-gui-v2/tailwind.config.js

@ -0,0 +1,8 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [],
theme: {
extend: {},
},
plugins: [],
}

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

@ -0,0 +1,5 @@
{
// https://v3.nuxtjs.org/concepts/typescript
"extends": "./.nuxt/tsconfig.json",
}
Loading…
Cancel
Save