Browse Source

refactor(gui-v2): cleanup project create utils

# What's changed?

* move form type to utils file
* move ClientType enum to enums file
* use ClientType enum where appropriate
* add default host (localhost)
* lint files
pull/2830/head
braks 2 years ago
parent
commit
13c35c4aca
  1. 8
      packages/nc-gui-v2/lib/enums.ts
  2. 40
      packages/nc-gui-v2/lib/types.ts
  3. 69
      packages/nc-gui-v2/pages/index/index.vue
  4. 14
      packages/nc-gui-v2/pages/project/index/create-external.vue
  5. 4
      packages/nc-gui-v2/pages/signin.vue
  6. 6
      packages/nc-gui-v2/pages/signup.vue
  7. 118
      packages/nc-gui-v2/utils/projectCreateUtils.ts

8
packages/nc-gui-v2/lib/enums.ts

@ -4,7 +4,13 @@ export enum Role {
User = 'user', User = 'user',
} }
export type Roles = Record<Role, boolean> export enum ClientType {
MYSQL = 'mysql2',
MSSQL = 'mssql',
PG = 'pg',
SQLITE = 'sqlite3',
VITESS = 'vitess',
}
export enum Language { export enum Language {
de = 'Deutsch', de = 'Deutsch',

40
packages/nc-gui-v2/lib/types.ts

@ -1,5 +1,5 @@
import type { ComputedRef, ToRefs } from 'vue' import type { ComputedRef, ToRefs } from 'vue'
import type { Roles } from '~/lib/enums' import type { Role } from './enums'
export interface User { export interface User {
id: string id: string
@ -33,40 +33,4 @@ export type ReadonlyState = Readonly<Pick<State, 'token' | 'user'>> & Omit<State
export type GlobalState = Getters & Actions & ToRefs<ReadonlyState> export type GlobalState = Getters & Actions & ToRefs<ReadonlyState>
export enum ClientType { export type Roles = Record<Role, boolean>
MYSQL = 'mysql2',
MSSQL = 'mssql',
PG = 'pg',
SQLITE = 'sqlite3',
VITESS = 'vitess',
}
export interface ProjectCreateForm {
title: string
dataSource: {
client: ClientType
connection:
| {
host: string
database: string
user: string
password: string
port: number | string
ssl?: Record<string, string>
searchPath?: string[]
}
| {
client?: 'sqlite3'
database: string
connection?: {
filename?: string
}
useNullAsDefault?: boolean
}
}
inflection: {
inflectionColumn?: string
inflectionTable?: string
}
sslUse?: any
}

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

@ -1,10 +1,10 @@
<script lang="ts" setup> <script lang="ts" setup>
import {Modal} from 'ant-design-vue' import { Modal } from 'ant-design-vue'
import type {ProjectType} from 'nocodb-sdk' import type { ProjectType } from 'nocodb-sdk'
import {useToast} from 'vue-toastification' import { useToast } from 'vue-toastification'
import {navigateTo} from '#app' import { navigateTo } from '#app'
import {computed, onMounted} from '#imports' import { computed, onMounted } from '#imports'
import {extractSdkResponseErrorMsg} from '~/utils/errorUtils' import { extractSdkResponseErrorMsg } from '~/utils/errorUtils'
import MdiDeleteOutline from '~icons/mdi/delete-outline' import MdiDeleteOutline from '~icons/mdi/delete-outline'
import MdiEditOutline from '~icons/mdi/edit-outline' import MdiEditOutline from '~icons/mdi/edit-outline'
@ -13,7 +13,7 @@ import MdiMenuDown from '~icons/mdi/menu-down'
import MdiPlus from '~icons/mdi/plus' import MdiPlus from '~icons/mdi/plus'
import MdiDatabaseOutline from '~icons/mdi/database-outline' import MdiDatabaseOutline from '~icons/mdi/database-outline'
const {$api, $state, $e} = useNuxtApp() const { $api, $state, $e } = useNuxtApp()
const toast = useToast() const toast = useToast()
const filterQuery = ref('') const filterQuery = ref('')
@ -29,7 +29,7 @@ const loadProjects = async () => {
const filteredProjects = computed(() => { const filteredProjects = computed(() => {
return projects.value.filter( return projects.value.filter(
(project) => !filterQuery.value || project.title?.toLowerCase?.().includes(filterQuery.value.toLowerCase()), (project) => !filterQuery.value || project.title?.toLowerCase?.().includes(filterQuery.value.toLowerCase()),
) )
}) })
@ -68,17 +68,17 @@ $state.sidebarOpen.value = false
<b>{{ $t('title.myProject') }}</b> <b>{{ $t('title.myProject') }}</b>
<MdiRefresh <MdiRefresh
v-t="['a:project:refresh']" v-t="['a:project:refresh']"
class="text-sm text-gray-500 hover:text-primary mt-1 cursor-pointer" class="text-sm text-gray-500 hover:text-primary mt-1 cursor-pointer"
@click="loadProjects" @click="loadProjects"
></MdiRefresh> ></MdiRefresh>
</h1> </h1>
<div class="flex mb-6"> <div class="flex mb-6">
<a-input-search <a-input-search
v-model:value="filterQuery" v-model:value="filterQuery"
class="max-w-[200px] nc-project-page-search" class="max-w-[200px] nc-project-page-search"
:placeholder="$t('activity.searchProject')" :placeholder="$t('activity.searchProject')"
></a-input-search> ></a-input-search>
<div class="flex-grow"></div> <div class="flex-grow"></div>
@ -86,27 +86,27 @@ $state.sidebarOpen.value = false
<a-button class="nc-new-project-menu !shadow"> <a-button class="nc-new-project-menu !shadow">
<div class="flex align-center"> <div class="flex align-center">
{{ $t('title.newProj') }} {{ $t('title.newProj') }}
<MdiMenuDown class="menu-icon"/> <MdiMenuDown class="menu-icon" />
</div> </div>
</a-button> </a-button>
<template #overlay> <template #overlay>
<a-menu> <a-menu>
<div <div
v-t="['c:project:create:xcdb']" v-t="['c:project:create:xcdb']"
class="grid grid-cols-12 cursor-pointer hover:bg-gray-200 flex items-center p-2 nc-create-xc-db-project" class="grid grid-cols-12 cursor-pointer hover:bg-gray-200 flex items-center p-2 nc-create-xc-db-project"
@click="navigateTo('/project/create')" @click="navigateTo('/project/create')"
> >
<MdiPlus class="col-span-2 mr-1 mt-[1px] text-primary text-lg"/> <MdiPlus class="col-span-2 mr-1 mt-[1px] text-primary text-lg" />
<div class="col-span-10 text-sm xl:text-md">{{ $t('activity.createProject') }}</div> <div class="col-span-10 text-sm xl:text-md">{{ $t('activity.createProject') }}</div>
</div> </div>
<div <div
v-t="['c:project:create:extdb']" v-t="['c:project:create:extdb']"
class="grid grid-cols-12 cursor-pointer hover:bg-gray-200 flex items-center p-2 nc-create-external-db-project" class="grid grid-cols-12 cursor-pointer hover:bg-gray-200 flex items-center p-2 nc-create-external-db-project"
@click="navigateTo('/project/create-external')" @click="navigateTo('/project/create-external')"
> >
<MdiDatabaseOutline class="col-span-2 mr-1 mt-[1px] text-green-500 text-lg"/> <MdiDatabaseOutline class="col-span-2 mr-1 mt-[1px] text-green-500 text-lg" />
<div class="col-span-10 text-sm xl:text-md" v-html="$t('activity.createProjectExtended.extDB')"/> <div class="col-span-10 text-sm xl:text-md" v-html="$t('activity.createProjectExtended.extDB')" />
</div> </div>
</a-menu> </a-menu>
</template> </template>
@ -114,12 +114,12 @@ $state.sidebarOpen.value = false
</div> </div>
<div v-if="loading"> <div v-if="loading">
<a-skeleton/> <a-skeleton />
</div> </div>
<a-table <a-table
v-else v-else
:custom-row=" :custom-row="
(record) => ({ (record) => ({
onClick: () => { onClick: () => {
$e('a:project:open') $e('a:project:open')
@ -127,14 +127,13 @@ $state.sidebarOpen.value = false
}, },
}) })
" "
:data-source="filteredProjects" :data-source="filteredProjects"
:pagination="{ position: ['bottomCenter'] }" :pagination="{ position: ['bottomCenter'] }"
> >
<!-- Title --> <!-- Title -->
<a-table-column key="title" :title="$t('general.title')" data-index="title"> <a-table-column key="title" :title="$t('general.title')" data-index="title">
<template #default="{ text }"> <template #default="{ text }">
<div class="capitalize !w-[400px] overflow-hidden overflow-ellipsis whitespace-nowrap nc-project-row" <div class="capitalize !w-[400px] overflow-hidden overflow-ellipsis whitespace-nowrap nc-project-row" :title="text">
:title="text">
{{ text }} {{ text }}
</div> </div>
</template> </template>
@ -144,11 +143,11 @@ $state.sidebarOpen.value = false
<template #default="{ text, record }"> <template #default="{ text, record }">
<div class="flex align-center"> <div class="flex align-center">
<MdiEditOutline <MdiEditOutline
v-t="['c:project:edit:rename']" v-t="['c:project:edit:rename']"
class="nc-action-btn" class="nc-action-btn"
@click.stop="navigateTo(`/project/${text}`)" @click.stop="navigateTo(`/project/${text}`)"
/> />
<MdiDeleteOutline class="nc-action-btn" @click.stop="deleteProject(record)"/> <MdiDeleteOutline class="nc-action-btn" @click.stop="deleteProject(record)" />
</div> </div>
</template> </template>
</a-table-column> </a-table-column>

14
packages/nc-gui-v2/pages/project/index/create-external.vue

@ -310,7 +310,7 @@ onMounted(() => {
<template #title> <template #title>
<span>{{ $t('tooltip.clientCert') }}</span> <span>{{ $t('tooltip.clientCert') }}</span>
</template> </template>
<a-button :disabled="!sslFilesRequired" size="small" @click="certFileInput.click()" class="shadow"> <a-button :disabled="!sslFilesRequired" size="small" class="shadow" @click="certFileInput.click()">
{{ $t('labels.clientCert') }} {{ $t('labels.clientCert') }}
</a-button> </a-button>
</a-tooltip> </a-tooltip>
@ -319,7 +319,7 @@ onMounted(() => {
<template #title> <template #title>
<span>{{ $t('tooltip.clientKey') }}</span> <span>{{ $t('tooltip.clientKey') }}</span>
</template> </template>
<a-button :disabled="!sslFilesRequired" size="small" @click="keyFileInput.click()" class="shadow"> <a-button :disabled="!sslFilesRequired" size="small" class="shadow" @click="keyFileInput.click()">
{{ $t('labels.clientKey') }} {{ $t('labels.clientKey') }}
</a-button> </a-button>
</a-tooltip> </a-tooltip>
@ -328,7 +328,7 @@ onMounted(() => {
<template #title> <template #title>
<span>{{ $t('tooltip.clientCA') }}</span> <span>{{ $t('tooltip.clientCA') }}</span>
</template> </template>
<a-button :disabled="!sslFilesRequired" size="small" @click="caFileInput.click()" class="shadow"> <a-button :disabled="!sslFilesRequired" size="small" class="shadow" @click="caFileInput.click()">
{{ $t('labels.serverCA') }} {{ $t('labels.serverCA') }}
</a-button> </a-button>
</a-tooltip> </a-tooltip>
@ -364,7 +364,9 @@ onMounted(() => {
<a-button type="primary" ghost class="nc-extdb-btn-test-connection" @click="testConnection"> <a-button type="primary" ghost class="nc-extdb-btn-test-connection" @click="testConnection">
{{ $t('activity.testDbConn') }} {{ $t('activity.testDbConn') }}
</a-button> </a-button>
<a-button type="primary" :disabled="!testSuccess" class="nc-extdb-btn-submit !shadow" @click="createProject"> Submit </a-button> <a-button type="primary" :disabled="!testSuccess" class="nc-extdb-btn-submit !shadow" @click="createProject">
Submit
</a-button>
</div> </div>
</a-form-item> </a-form-item>
</a-form> </a-form>
@ -398,7 +400,7 @@ onMounted(() => {
@apply !min-h-0; @apply !min-h-0;
} }
:deep(.ant-card-head-title){ :deep(.ant-card-head-title) {
@apply !text-3xl @apply !text-3xl;
} }
</style> </style>

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

@ -111,7 +111,9 @@ const resetError = () => {
</nuxt-link> </nuxt-link>
</div> </div>
<div class="self-center flex flex-column flex-wrap gap-4 items-center mt-4 md:mx-8 md:justify-between justify-center w-full"> <div
class="self-center flex flex-column flex-wrap gap-4 items-center mt-4 md:mx-8 md:justify-between justify-center w-full"
>
<button class="submit" type="submit"> <button class="submit" type="submit">
<span class="flex items-center gap-2"><MdiLogin /> {{ $t('general.signIn') }}</span> <span class="flex items-center gap-2"><MdiLogin /> {{ $t('general.signIn') }}</span>
</button> </button>

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

@ -19,7 +19,7 @@ let error = $ref<string | null>(null)
const form = reactive({ const form = reactive({
email: '', email: '',
password: '' password: '',
}) })
const formRules = { const formRules = {
@ -102,7 +102,9 @@ const resetError = () => {
/> />
</a-form-item> </a-form-item>
<div class="self-center flex flex-column flex-wrap gap-4 items-center mt-4 md:mx-8 md:justify-between justify-center w-full"> <div
class="self-center flex flex-column flex-wrap gap-4 items-center mt-4 md:mx-8 md:justify-between justify-center w-full"
>
<button class="submit" type="submit"> <button class="submit" type="submit">
<span class="flex items-center gap-2"><MaterialSymbolsRocketLaunchOutline /> {{ $t('general.signUp') }}</span> <span class="flex items-center gap-2"><MaterialSymbolsRocketLaunchOutline /> {{ $t('general.signUp') }}</span>
</button> </button>

118
packages/nc-gui-v2/utils/projectCreateUtils.ts

@ -1,43 +1,75 @@
import { adjectives, animals, starWars, uniqueNamesGenerator } from 'unique-names-generator' import { adjectives, animals, starWars, uniqueNamesGenerator } from 'unique-names-generator'
import type { ClientType, ProjectCreateForm } from '~/lib/types' import { ClientType } from '~/lib/enums'
export interface ProjectCreateForm {
title: string
dataSource: {
client: ClientType
connection:
| {
host: string
database: string
user: string
password: string
port: number | string
ssl?: Record<string, string>
searchPath?: string[]
}
| {
client?: ClientType.SQLITE
database: string
connection?: {
filename?: string
}
useNullAsDefault?: boolean
}
}
inflection: {
inflectionColumn?: string
inflectionTable?: string
}
sslUse?: any
}
const defaultHost = 'localhost'
const testDataBaseNames = { const testDataBaseNames = {
mysql2: null, [ClientType.MYSQL]: null,
mysql: null, mysql: null,
pg: 'postgres', [ClientType.PG]: 'postgres',
oracledb: 'xe', oracledb: 'xe',
mssql: undefined, [ClientType.MSSQL]: undefined,
sqlite3: 'a.sqlite', [ClientType.SQLITE]: 'a.sqlite',
} }
export const getTestDatabaseName = (db: { client: ClientType; connection?: { database?: string } }) => { export const getTestDatabaseName = (db: { client: ClientType; connection?: { database?: string } }) => {
if (db.client === 'pg') return db.connection?.database if (db.client === ClientType.PG) return db.connection?.database
return testDataBaseNames[db.client as keyof typeof testDataBaseNames] return testDataBaseNames[db.client as keyof typeof testDataBaseNames]
} }
export const clientTypes = [ export const clientTypes = [
{ {
text: 'MySql', text: 'MySql',
value: 'mysql2', value: ClientType.MYSQL,
}, },
{ {
text: 'MSSQL', text: 'MSSQL',
value: 'mssql', value: ClientType.MSSQL,
}, },
{ {
text: 'PostgreSQL', text: 'PostgreSQL',
value: 'pg', value: ClientType.PG,
}, },
{ {
text: 'SQLite', text: 'SQLite',
value: 'sqlite3', value: ClientType.SQLITE,
}, },
] ]
const homeDir = '' const homeDir = ''
const sampleConnectionData: Record<ClientType | string, ProjectCreateForm['dataSource']['connection']> = { const sampleConnectionData: Record<ClientType | string, ProjectCreateForm['dataSource']['connection']> = {
pg: { [ClientType.PG]: {
host: 'localhost', host: defaultHost,
port: '5432', port: '5432',
user: 'postgres', user: 'postgres',
password: 'password', password: 'password',
@ -49,8 +81,8 @@ const sampleConnectionData: Record<ClientType | string, ProjectCreateForm['dataS
cert: '', cert: '',
}, },
}, },
mysql2: { [ClientType.MYSQL]: {
host: 'localhost', host: defaultHost,
port: '3306', port: '3306',
user: 'root', user: 'root',
password: 'password', password: 'password',
@ -61,8 +93,8 @@ const sampleConnectionData: Record<ClientType | string, ProjectCreateForm['dataS
cert: '', cert: '',
}, },
}, },
vitess: { [ClientType.VITESS]: {
host: 'localhost', host: defaultHost,
port: '15306', port: '15306',
user: 'root', user: 'root',
password: 'password', password: 'password',
@ -73,8 +105,29 @@ const sampleConnectionData: Record<ClientType | string, ProjectCreateForm['dataS
cert: '', cert: '',
}, },
}, },
[ClientType.MSSQL]: {
host: defaultHost,
port: 1433,
user: 'sa',
password: 'Password123.',
database: '_test',
searchPath: ['dbo'],
ssl: {
ca: '',
key: '',
cert: '',
},
},
[ClientType.SQLITE]: {
client: ClientType.SQLITE,
database: homeDir,
connection: {
filename: homeDir,
},
useNullAsDefault: true,
},
tidb: { tidb: {
host: 'localhost', host: defaultHost,
port: '4000', port: '4000',
user: 'root', user: 'root',
password: '', password: '',
@ -86,7 +139,7 @@ const sampleConnectionData: Record<ClientType | string, ProjectCreateForm['dataS
}, },
}, },
yugabyte: { yugabyte: {
host: 'localhost', host: defaultHost,
port: '5432', port: '5432',
user: 'postgres', user: 'postgres',
password: '', password: '',
@ -98,7 +151,7 @@ const sampleConnectionData: Record<ClientType | string, ProjectCreateForm['dataS
}, },
}, },
citusdb: { citusdb: {
host: 'localhost', host: defaultHost,
port: '5432', port: '5432',
user: 'postgres', user: 'postgres',
password: '', password: '',
@ -110,7 +163,7 @@ const sampleConnectionData: Record<ClientType | string, ProjectCreateForm['dataS
}, },
}, },
cockroachdb: { cockroachdb: {
host: 'localhost', host: defaultHost,
port: '5432', port: '5432',
user: 'postgres', user: 'postgres',
password: '', password: '',
@ -122,7 +175,7 @@ const sampleConnectionData: Record<ClientType | string, ProjectCreateForm['dataS
}, },
}, },
greenplum: { greenplum: {
host: 'localhost', host: defaultHost,
port: '5432', port: '5432',
user: 'postgres', user: 'postgres',
password: '', password: '',
@ -133,21 +186,8 @@ const sampleConnectionData: Record<ClientType | string, ProjectCreateForm['dataS
cert: '', cert: '',
}, },
}, },
mssql: {
host: 'localhost',
port: 1433,
user: 'sa',
password: 'Password123.',
database: '_test',
searchPath: ['dbo'],
ssl: {
ca: '',
key: '',
cert: '',
},
},
oracledb: { oracledb: {
host: 'localhost', host: defaultHost,
port: '1521', port: '1521',
user: 'system', user: 'system',
password: 'Oracle18', password: 'Oracle18',
@ -158,14 +198,6 @@ const sampleConnectionData: Record<ClientType | string, ProjectCreateForm['dataS
cert: '', cert: '',
}, },
}, },
sqlite3: {
client: 'sqlite3',
database: homeDir,
connection: {
filename: homeDir,
},
useNullAsDefault: true,
},
} }
export const getDefaultConnectionConfig = (client: ClientType): ProjectCreateForm['dataSource'] => { export const getDefaultConnectionConfig = (client: ClientType): ProjectCreateForm['dataSource'] => {

Loading…
Cancel
Save