mirror of https://github.com/nocodb/nocodb
github-actions[bot]
2 years ago
committed by
GitHub
88 changed files with 26866 additions and 13163 deletions
@ -0,0 +1,40 @@
|
||||
# This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node |
||||
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions |
||||
|
||||
name: Backend Unit Tests |
||||
|
||||
on: |
||||
push: |
||||
branches: [ "develop" ] |
||||
pull_request: |
||||
branches: [ "develop" ] |
||||
|
||||
jobs: |
||||
unit-tests: |
||||
|
||||
runs-on: ubuntu-latest |
||||
|
||||
strategy: |
||||
matrix: |
||||
node-version: [16.x] |
||||
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/ |
||||
|
||||
steps: |
||||
- uses: actions/checkout@v3 |
||||
- name: Use Node.js ${{ matrix.node-version }} |
||||
uses: actions/setup-node@v3 |
||||
with: |
||||
node-version: ${{ matrix.node-version }} |
||||
cache: 'npm' |
||||
- name: install dependencies nocodb-sdk |
||||
working-directory: ./packages/nocodb-sdk |
||||
run: npm ci |
||||
- name: build nocodb-sdk |
||||
working-directory: ./packages/nocodb-sdk |
||||
run: npm run build:main |
||||
- name: install dependencies nocodb |
||||
working-directory: ./packages/nocodb |
||||
run: npm ci |
||||
- name: run unit tests |
||||
working-directory: ./packages/nocodb |
||||
run: npm run unit-test |
@ -0,0 +1,8 @@
|
||||
node_modules |
||||
*.log* |
||||
.nuxt |
||||
.nitro |
||||
.cache |
||||
.output |
||||
.env |
||||
dist |
@ -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. |
@ -0,0 +1,6 @@
|
||||
<template> |
||||
<!-- <NuxtLayout>--> |
||||
<!-- <NuxtPage />--> |
||||
<!-- </NuxtLayout>--> |
||||
<NuxtPage/> |
||||
</template> |
After Width: | Height: | Size: 67 KiB |
@ -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> |
@ -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> |
@ -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> |
@ -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> |
@ -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} |
||||
} |
@ -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} |
||||
} |
@ -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} |
||||
} |
@ -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} |
||||
} |
@ -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' |
||||
} |
@ -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> |
@ -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', |
||||
} |
||||
} |
||||
}) |
File diff suppressed because it is too large
Load Diff
@ -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" |
||||
} |
||||
} |
@ -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> |
@ -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> |
@ -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> |
@ -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> |
@ -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> |
@ -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> |
@ -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> |
@ -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)
|
||||
// }
|
@ -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
|
||||
}); |
@ -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)
|
||||
}) |
@ -0,0 +1,8 @@
|
||||
/** @type {import('tailwindcss').Config} */ |
||||
module.exports = { |
||||
content: [], |
||||
theme: { |
||||
extend: {}, |
||||
}, |
||||
plugins: [], |
||||
} |
@ -0,0 +1,5 @@
|
||||
{ |
||||
// https://v3.nuxtjs.org/concepts/typescript |
||||
"extends": "./.nuxt/tsconfig.json", |
||||
|
||||
} |
@ -1,14 +0,0 @@
|
||||
--- |
||||
title: 'GraphQL APIs' |
||||
position: 1020 |
||||
category: 'Developer Resources' |
||||
menuTitle: 'GraphQL APIs' |
||||
--- |
||||
|
||||
<alert type="danger"> |
||||
GraphQL APIs, unfortunately, has been deprecated form v0.90 onwards - which means |
||||
|
||||
- Users won't be able to create a GraphQL project nor use the GraphQL queries. |
||||
- For projects created before v0.90, we will convert it to REST API projects. |
||||
- The rationale behind is that GraphQL is a really small use case of NocoDB users and smart spreadsheet are usually flat representation of data (may be one level nested) which means there will be additional wrangling of json and GQL schema when users are changing the schema dynamically. |
||||
</alert> |
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,80 @@
|
||||
'use strict'; |
||||
|
||||
import rewire from 'rewire'; |
||||
import sinon from 'sinon'; |
||||
import { expect } from 'chai'; |
||||
import Base from '../../../../../../lib/models/Base'; |
||||
import Model from '../../../../../../lib/models/Model'; |
||||
import NcConnectionMgrv2 from '../../../../../../lib/utils/common/NcConnectionMgrv2'; |
||||
import * as getAstObject from '../../../../../../lib/db/sql-data-mapper/lib/sql/helpers/getAst'; |
||||
|
||||
const dataAliasApis = rewire( |
||||
'../../../../../../lib/meta/api/dataApis/dataAliasApis' |
||||
); |
||||
const getFindOne = dataAliasApis.__get__('getFindOne'); |
||||
|
||||
describe('getFindOne', () => { |
||||
const model = { |
||||
id: 'modelId', |
||||
base_id: 'baseId' |
||||
}; |
||||
const view = { |
||||
id: 'viewId' |
||||
}; |
||||
const base = { |
||||
id: 'baseId' |
||||
}; |
||||
const dbDriver = { |
||||
id: 'dbDriverId' |
||||
}; |
||||
const req = { query: {} }; |
||||
const baseModel = { |
||||
findOne: sinon.fake.returns(undefined) |
||||
}; |
||||
const baseGetFake = sinon.replace(Base, 'get', sinon.fake.returns(base)); |
||||
const baseModelFake = sinon.replace( |
||||
Model, |
||||
'getBaseModelSQL', |
||||
sinon.fake.returns(baseModel) |
||||
); |
||||
sinon.replace(NcConnectionMgrv2, 'get', sinon.fake.returns(dbDriver)); |
||||
const getAstFake = sinon.fake.returns({ id: 1 }); |
||||
sinon.replace(getAstObject, 'default', getAstFake); |
||||
|
||||
it('calls Base.get to find base', async () => { |
||||
await getFindOne(model, view, req); |
||||
expect(baseGetFake.calledWith(model.base_id)).to.be.true; |
||||
}); |
||||
|
||||
it('call Model.getBaseModelSQL to find baseModel', async () => { |
||||
await getFindOne(model, view, req); |
||||
expect( |
||||
baseModelFake.calledWith({ |
||||
id: model.id, |
||||
viewId: view.id, |
||||
dbDriver: dbDriver |
||||
}) |
||||
).to.be.true; |
||||
}); |
||||
|
||||
it('calls baseModel.findOne', async () => { |
||||
await getFindOne(model, view, req); |
||||
expect(baseModel.findOne.calledWith({ ...req.query })).to.be.true; |
||||
}); |
||||
|
||||
describe('when data is not found', () => { |
||||
it('should return empty object', async () => { |
||||
expect(await getFindOne(model, view, req)).to.be.empty; |
||||
}); |
||||
}); |
||||
|
||||
describe('when data is found', () => { |
||||
it('returns data', async () => { |
||||
const findOneResult = { |
||||
id: 'dataId' |
||||
}; |
||||
baseModel.findOne = sinon.fake.returns(findOneResult); |
||||
expect(await getFindOne(model, view, req)).eql(findOneResult); |
||||
}); |
||||
}); |
||||
}); |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,49 @@
|
||||
import cors from 'cors'; |
||||
import express from 'express'; |
||||
|
||||
import Noco from '../lib/Noco'; |
||||
process.env.NC_VERSION = '0009044'; |
||||
|
||||
const server = express(); |
||||
server.use( |
||||
cors({ |
||||
exposedHeaders: 'xc-db-response', |
||||
}) |
||||
); |
||||
|
||||
server.set('view engine', 'ejs'); |
||||
process.env[ |
||||
`NC_DB` |
||||
] = `pg://localhost:5432?u=postgres&p=password&d=meta_v2_2022_06_13`; |
||||
|
||||
process.env[`DEBUG`] = 'xc*'; |
||||
|
||||
(async () => { |
||||
const httpServer = server.listen(process.env.PORT || 8080, () => { |
||||
console.log(`App started successfully.\nVisit -> ${Noco.dashboardUrl}`); |
||||
}); |
||||
server.use(await Noco.init({}, httpServer, server)); |
||||
})().catch((e) => console.log(e)); |
||||
|
||||
/** |
||||
* @copyright Copyright (c) 2021, Xgene Cloud Ltd |
||||
* |
||||
* @author Naveen MR <oof1lab@gmail.com> |
||||
* @author Pranav C Balan <pranavxc@gmail.com> |
||||
* |
||||
* @license GNU AGPL version 3 or any later version |
||||
* |
||||
* This program is free software: you can redistribute it and/or modify |
||||
* it under the terms of the GNU Affero General Public License as |
||||
* published by the Free Software Foundation, either version 3 of the |
||||
* License, or (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU Affero General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Affero General Public License |
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
* |
||||
*/ |
@ -1,6 +1,7 @@
|
||||
{ |
||||
"srcProject": "sample", |
||||
"dstProject": "sample-copy", |
||||
"excludeDt": true, |
||||
"baseURL": "http://localhost:8080", |
||||
"xc-auth": "Copy Auth Token" |
||||
} |
Loading…
Reference in new issue