Browse Source

Merge pull request #3538 from nocodb/develop

pull/3539/head
github-actions[bot] 2 years ago committed by GitHub
parent
commit
320f70d446
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 3
      crowdin.yml
  2. 30
      packages/nc-gui/components/general/ReleaseInfo.vue
  3. 5
      packages/nc-gui/composables/useApi/index.ts
  4. 3
      packages/nc-gui/composables/useGlobal/state.ts
  5. 1
      packages/nc-gui/lib/constants.ts
  6. 2
      packages/nc-gui/pages/index/index/create-external.vue
  7. 29
      packages/nocodb/src/__tests__/noco/NcConfigFactory.test.ts
  8. 77
      packages/nocodb/src/lib/utils/NcConfigFactory.ts

3
crowdin.yml

@ -0,0 +1,3 @@
files:
- source: /packages/nc-gui/lang/en.json
translation: /packages/nc-gui/lang/%two_letters_code%.json

30
packages/nc-gui/components/general/ReleaseInfo.vue

@ -6,13 +6,19 @@ const { $api } = useNuxtApp()
const { currentVersion, latestRelease, hiddenRelease } = useGlobal()
const releaseAlert = computed(
() =>
currentVersion.value &&
latestRelease.value &&
currentVersion.value !== latestRelease.value &&
latestRelease.value !== hiddenRelease.value,
)
const releaseAlert = computed({
get() {
return (
currentVersion.value &&
latestRelease.value &&
currentVersion.value !== latestRelease.value &&
latestRelease.value !== hiddenRelease.value
)
},
set(val) {
hiddenRelease.value = val ? null : latestRelease.value
},
})
async function fetchReleaseInfo() {
try {
@ -35,7 +41,7 @@ onMounted(async () => await fetchReleaseInfo())
<template>
<div v-if="releaseAlert" class="flex items-center">
<a-dropdown :trigger="['click']" placement="bottom">
<a-button class="bg-primary border-none">
<a-button class="!bg-primary !border-none">
<div class="flex gap-1 items-center text-white">
<span class="text-sm font-weight-medium">{{ $t('activity.upgrade.available') }}</span>
<mdi-menu-down />
@ -43,21 +49,21 @@ onMounted(async () => await fetchReleaseInfo())
</a-button>
<template #overlay>
<div class="mt-1 bg-white shadow-lg !border">
<nuxt-link class="text-primary" to="https://github.com/nocodb/nocodb/releases" target="_blank">
<nuxt-link class="!text-primary !no-underline" to="https://github.com/nocodb/nocodb/releases" target="_blank">
<div class="nc-menu-item">
<mdi-script-text-outline />
{{ latestRelease }} {{ $t('activity.upgrade.releaseNote') }}
</div>
</nuxt-link>
<nuxt-link class="text-primary" to="https://docs.nocodb.com/getting-started/upgrading" target="_blank">
<nuxt-link class="!text-primary !no-underline" to="https://docs.nocodb.com/getting-started/upgrading" target="_blank">
<div class="nc-menu-item">
<mdi-rocket-launch-outline />
<!-- How to upgrade? -->
{{ $t('activity.upgrade.howTo') }}
</div>
</nuxt-link>
<a-divider class="m-0" />
<div class="nc-menu-item" @click="latestRelease = null">
<a-divider class="!m-0" />
<div class="nc-menu-item" @click="releaseAlert = false">
<mdi-close />
<!-- Hide menu -->
{{ $t('general.hideMenu') }}

5
packages/nc-gui/composables/useApi/index.ts

@ -3,14 +3,15 @@ import { Api } from 'nocodb-sdk'
import type { Ref } from 'vue'
import type { CreateApiOptions, UseApiProps, UseApiReturn } from './types'
import { addAxiosInterceptors } from './interceptors'
import { BASE_URL } from '~/lib'
import { createEventHook, ref, unref, useCounter, useGlobal, useNuxtApp } from '#imports'
export function createApiInstance<SecurityDataType = any>(options: CreateApiOptions = {}): Api<SecurityDataType> {
export function createApiInstance<SecurityDataType = any>({ baseURL = BASE_URL }: CreateApiOptions = {}): Api<SecurityDataType> {
const { appInfo } = $(useGlobal())
return addAxiosInterceptors(
new Api<SecurityDataType>({
baseURL: options.baseURL ?? appInfo.ncSiteUrl,
baseURL: baseURL ?? appInfo.ncSiteUrl,
}),
)
}

3
packages/nc-gui/composables/useGlobal/state.ts

@ -2,6 +2,7 @@ import { usePreferredLanguages, useStorage } from '@vueuse/core'
import { useJwt } from '@vueuse/integrations/useJwt'
import type { JwtPayload } from 'jwt-decode'
import type { AppInfo, State, StoredState } from './types'
import { BASE_URL } from '~/lib'
import { computed, ref, toRefs, useCounter, useNuxtApp, useTimestamp } from '#imports'
import type { User } from '~/lib'
@ -77,7 +78,7 @@ export function useGlobalState(storageKey = 'nocodb-gui-v2'): State {
})
const appInfo = ref<AppInfo>({
ncSiteUrl: process.env.NC_BACKEND_URL || (process.env.NODE_ENV === 'production' ? '..' : 'http://localhost:8080'),
ncSiteUrl: BASE_URL,
authType: 'jwt',
connectToExternalDB: false,
defaultLimit: 0,

1
packages/nc-gui/lib/constants.ts

@ -1,3 +1,4 @@
export const NOCO = 'noco'
export const USER_PROJECT_ROLES = 'user_project_roles'
export const SYSTEM_COLUMNS = ['id', 'title', 'created_at', 'updated_at']
export const BASE_URL = process.env.NC_BACKEND_URL || (process.env.NODE_ENV === 'production' ? '..' : 'http://localhost:8080')

2
packages/nc-gui/pages/index/index/create-external.vue

@ -181,7 +181,7 @@ function getConnectionConfig() {
if ('ssl' in connection && connection.ssl) {
if (
formState.sslUse === SSLUsage.No ||
(typeof connection.ssl === 'object' && Object.values(connection.ssl).every((v) => !v))
(typeof connection.ssl === 'object' && Object.values(connection.ssl).every((v) => v === null || v === undefined))
) {
delete connection.ssl
}

29
packages/nocodb/src/__tests__/noco/NcConfigFactory.test.ts

@ -38,6 +38,35 @@ describe('Config Factory Tests', () => {
expect(dbConfig).to.deep.equal(rest);
done();
});
it('Generate config from DATABASE_URL', function (done) {
// postgres url
const ncDbUrl = NcConfigFactory.extractXcUrlFromJdbc(
'postgres://username:password@host:5432/db'
);
expect(ncDbUrl).to.be.equal('pg://host:5432?u=username&p=password&d=db&');
// postgres url without port
const ncDbUrl1 = NcConfigFactory.extractXcUrlFromJdbc(
'postgres://username:password@host/db'
);
expect(ncDbUrl1).to.be.equal('pg://host:5432?u=username&p=password&d=db&');
// mysql url
const ncDbUrl2 = NcConfigFactory.extractXcUrlFromJdbc(
'jdbc:mysql://localhost/sample_db'
);
expect(ncDbUrl2).to.be.equal('mysql2://localhost:3306?d=sample_db&');
// mariadb url
const ncDbUrl3 = NcConfigFactory.extractXcUrlFromJdbc(
'jdbc:mariadb://localhost/sample_db'
);
expect(ncDbUrl3).to.be.equal('mysql2://localhost:3306?d=sample_db&');
done();
});
it('Connection string with nested property', function (done) {
const dbConfig = NcConfigFactory.metaUrlToDbConfig(
`pg://localhost:5432?u=postgres&p=xgene&d=abcde&pool.min=1&pool.max=2&ssl.rejectUnauthorized=false`

77
packages/nocodb/src/lib/utils/NcConfigFactory.ts

@ -20,6 +20,7 @@ const {
const driverClientMapping = {
mysql: 'mysql2',
mariadb: 'mysql2',
postgres: 'pg',
postgresql: 'pg',
sqlite: 'sqlite3',
@ -59,23 +60,23 @@ const knownQueryParams = [
},
{
parameter: 'keyFilePath',
aliases: []
aliases: [],
},
{
parameter: 'certFilePath',
aliases: []
aliases: [],
},
{
parameter: 'caFilePath',
aliases: []
aliases: [],
},
{
parameter: 'ssl',
aliases: []
aliases: [],
},
{
parameter: 'options',
aliases: ['opt', 'opts']
aliases: ['opt', 'opts'],
},
];
@ -195,9 +196,11 @@ export default class NcConfigFactory implements NcConfig {
},
} as any;
} else {
const parsedQuery = {}
const parsedQuery = {};
for (const [key, value] of url.searchParams.entries()) {
const fnd = knownQueryParams.find((param) => param.parameter === key || param.aliases.includes(key))
const fnd = knownQueryParams.find(
(param) => param.parameter === key || param.aliases.includes(key)
);
if (fnd) {
parsedQuery[fnd.parameter] = value;
} else {
@ -209,7 +212,8 @@ export default class NcConfigFactory implements NcConfig {
client: url.protocol.replace(':', ''),
connection: {
...defaultConnectionConfig,
...parsedQuery
...parsedQuery,
host: url.hostname,
},
// pool: {
// min: 1,
@ -303,9 +307,11 @@ export default class NcConfigFactory implements NcConfig {
: {}),
};
} else {
const parsedQuery = {}
const parsedQuery = {};
for (const [key, value] of url.searchParams.entries()) {
const fnd = knownQueryParams.find((param) => param.parameter === key || param.aliases.includes(key))
const fnd = knownQueryParams.find(
(param) => param.parameter === key || param.aliases.includes(key)
);
if (fnd) {
parsedQuery[fnd.parameter] = value;
} else {
@ -317,7 +323,8 @@ export default class NcConfigFactory implements NcConfig {
client: url.protocol.replace(':', ''),
connection: {
...defaultConnectionConfig,
...parsedQuery
...parsedQuery,
host: url.hostname,
},
acquireConnectionTimeout: 600000,
...(url.searchParams.has('search_path')
@ -636,7 +643,7 @@ export default class NcConfigFactory implements NcConfig {
}
}
public static extractXcUrlFromJdbc(url: string, rtConfig: boolean = false) {
public static extractXcUrlFromJdbc(url: string, rtConfig = false) {
// drop the jdbc prefix
if (url.startsWith('jdbc:')) {
url = url.substring(5);
@ -644,9 +651,19 @@ export default class NcConfigFactory implements NcConfig {
const config = parseDbUrl(url);
const parsedConfig: { driver?: string, host?: string, port?: string, database?: string, user?:string, password?: string, ssl?: string } = {}
const parsedConfig: {
driver?: string;
host?: string;
port?: string;
database?: string;
user?: string;
password?: string;
ssl?: string;
} = {};
for (const [key, value] of Object.entries(config)) {
const fnd = knownQueryParams.find((param) => param.parameter === key || param.aliases.includes(key))
const fnd = knownQueryParams.find(
(param) => param.parameter === key || param.aliases.includes(key)
);
if (fnd) {
parsedConfig[fnd.parameter] = value;
} else {
@ -654,28 +671,42 @@ export default class NcConfigFactory implements NcConfig {
}
}
if (!parsedConfig?.port) parsedConfig.port = defaultClientPortMapping[driverClientMapping[parsedConfig.driver] || parsedConfig.driver];
if (!parsedConfig?.port)
parsedConfig.port =
defaultClientPortMapping[
driverClientMapping[parsedConfig.driver] || parsedConfig.driver
];
if (rtConfig) {
const { driver, ...connectionConfig } = parsedConfig;
const client = driverClientMapping[driver] || driver;
const avoidSSL = ['localhost', '127.0.0.1', 'host.docker.internal', '172.17. 0.1']
const avoidSSL = [
'localhost',
'127.0.0.1',
'host.docker.internal',
'172.17.0.1',
];
if (client === 'pg' && !connectionConfig?.ssl && !avoidSSL.includes(connectionConfig.host)) {
if (
client === 'pg' &&
!connectionConfig?.ssl &&
!avoidSSL.includes(connectionConfig.host)
) {
connectionConfig.ssl = 'true';
}
return {
client: client,
connection: {
...connectionConfig
}
...connectionConfig,
},
} as any;
}
const { driver, host, port, database, user, password, ...extra } = parsedConfig;
const { driver, host, port, database, user, password, ...extra } =
parsedConfig;
const extraParams = [];
@ -683,7 +714,11 @@ export default class NcConfigFactory implements NcConfig {
extraParams.push(`${key}=${value}`);
}
const res = `${driverClientMapping[driver] || driver}://${host}${port ? `:${port}` : ''}?${user ? `u=${user}&` : ''}${password ? `p=${password}&` : ''}${database ? `d=${database}&` : ''}${extraParams.join('&')}`;
const res = `${driverClientMapping[driver] || driver}://${host}${
port ? `:${port}` : ''
}?${user ? `u=${user}&` : ''}${password ? `p=${password}&` : ''}${
database ? `d=${database}&` : ''
}${extraParams.join('&')}`;
return res;
}

Loading…
Cancel
Save