diff --git a/packages/nc-gui/composables/useApi/index.ts b/packages/nc-gui/composables/useApi/index.ts index 444c1bb401..532d785871 100644 --- a/packages/nc-gui/composables/useApi/index.ts +++ b/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(options: CreateApiOptions = {}): Api { +export function createApiInstance({ baseURL = BASE_URL }: CreateApiOptions = {}): Api { const { appInfo } = $(useGlobal()) return addAxiosInterceptors( new Api({ - baseURL: options.baseURL ?? appInfo.ncSiteUrl, + baseURL: baseURL ?? appInfo.ncSiteUrl, }), ) } diff --git a/packages/nc-gui/composables/useGlobal/state.ts b/packages/nc-gui/composables/useGlobal/state.ts index 037a9f84ca..56316f62fb 100644 --- a/packages/nc-gui/composables/useGlobal/state.ts +++ b/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({ - ncSiteUrl: process.env.NC_BACKEND_URL || (process.env.NODE_ENV === 'production' ? '..' : 'http://localhost:8080'), + ncSiteUrl: BASE_URL, authType: 'jwt', connectToExternalDB: false, defaultLimit: 0, diff --git a/packages/nc-gui/lib/constants.ts b/packages/nc-gui/lib/constants.ts index 7b6465b2aa..875684598d 100644 --- a/packages/nc-gui/lib/constants.ts +++ b/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') diff --git a/packages/nc-gui/pages/index/index/create-external.vue b/packages/nc-gui/pages/index/index/create-external.vue index 4943d09ddf..e73d5c004b 100644 --- a/packages/nc-gui/pages/index/index/create-external.vue +++ b/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 } diff --git a/packages/nocodb/src/__tests__/noco/NcConfigFactory.test.ts b/packages/nocodb/src/__tests__/noco/NcConfigFactory.test.ts index 10956a2188..04394bff8d 100644 --- a/packages/nocodb/src/__tests__/noco/NcConfigFactory.test.ts +++ b/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` diff --git a/packages/nocodb/src/lib/utils/NcConfigFactory.ts b/packages/nocodb/src/lib/utils/NcConfigFactory.ts index d3aa41b63e..3cfc471ca7 100644 --- a/packages/nocodb/src/lib/utils/NcConfigFactory.ts +++ b/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'] - if (client === 'pg' && !connectionConfig?.ssl && !avoidSSL.includes(connectionConfig.host)) { + const avoidSSL = [ + 'localhost', + '127.0.0.1', + 'host.docker.internal', + '172.17.0.1', + ]; + + 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; }