From 9083f185f836257f0962425c03f5faca73580188 Mon Sep 17 00:00:00 2001 From: Pranav C Date: Sat, 24 Dec 2022 11:42:42 +0530 Subject: [PATCH 01/10] fix(gui): rerender component when title changes re #4686 - lengthy view name needs to be truncated in toolbar view Signed-off-by: Pranav C --- packages/nc-gui/components.d.ts | 1 + packages/nc-gui/components/smartsheet/toolbar/ViewActions.vue | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/nc-gui/components.d.ts b/packages/nc-gui/components.d.ts index bb95e0722e..87d8ad7140 100644 --- a/packages/nc-gui/components.d.ts +++ b/packages/nc-gui/components.d.ts @@ -90,6 +90,7 @@ declare module '@vue/runtime-core' { LogosMysqlIcon: typeof import('~icons/logos/mysql-icon')['default'] LogosPostgresql: typeof import('~icons/logos/postgresql')['default'] LogosRedditIcon: typeof import('~icons/logos/reddit-icon')['default'] + LogosSnowflakeIcon: typeof import('~icons/logos/snowflake-icon')['default'] LogosSwagger: typeof import('~icons/logos/swagger')['default'] MaterialSymbolsAccountTreeRounded: typeof import('~icons/material-symbols/account-tree-rounded')['default'] MaterialSymbolsArrowCircleLeftRounded: typeof import('~icons/material-symbols/arrow-circle-left-rounded')['default'] diff --git a/packages/nc-gui/components/smartsheet/toolbar/ViewActions.vue b/packages/nc-gui/components/smartsheet/toolbar/ViewActions.vue index 83cf7acb2d..41255b30a5 100644 --- a/packages/nc-gui/components/smartsheet/toolbar/ViewActions.vue +++ b/packages/nc-gui/components/smartsheet/toolbar/ViewActions.vue @@ -95,7 +95,7 @@ useMenuCloseOnEsc(open) - {{ selectedView?.title }} + {{ selectedView?.title }} From c841c767f0ed5e80703ef6d6bda908e11d061d91 Mon Sep 17 00:00:00 2001 From: Pranav C Date: Sat, 24 Dec 2022 13:10:00 +0530 Subject: [PATCH 02/10] fix(gui): stop event propagation in view rename input re #4686 Signed-off-by: Pranav C --- .../nc-gui/components/dashboard/TreeView.vue | 7 +- .../smartsheet/sidebar/RenameableMenuItem.vue | 2 +- .../nc-gui/composables/useGlobal/types.ts | 1 + .../pages/index/index/create-external.vue | 82 ++++++++++++------- packages/nocodb/src/lib/Noco.ts | 16 ++++ .../lib/db/sql-client/lib/SqlClientFactory.ts | 19 +++-- .../sql-client/lib/ee/SqlClientFactoryEE.ts | 19 +++++ packages/nocodb/src/lib/meta/api/utilApis.ts | 3 + .../lib/migrations/v2/nc_013_sync_source.ts | 1 + 9 files changed, 109 insertions(+), 41 deletions(-) create mode 100644 packages/nocodb/src/lib/db/sql-client/lib/ee/SqlClientFactoryEE.ts diff --git a/packages/nc-gui/components/dashboard/TreeView.vue b/packages/nc-gui/components/dashboard/TreeView.vue index d8bfa0e807..eb8e93eca2 100644 --- a/packages/nc-gui/components/dashboard/TreeView.vue +++ b/packages/nc-gui/components/dashboard/TreeView.vue @@ -26,6 +26,7 @@ import { useToggle, useUIPermission, watchEffect, + useGlobal } from '#imports' import MdiView from '~icons/mdi/eye-circle-outline' import MdiTableLarge from '~icons/mdi/table-large' @@ -46,6 +47,8 @@ const route = useRoute() const [searchActive, toggleSearchActive] = useToggle() +const { appInfo } = useGlobal() + const toggleDialog = inject(ToggleDialogInj, () => {}) const keys = $ref>({}) @@ -414,7 +417,7 @@ const setIcon = async (icon: string, table: TableType) => { MSSQL - +
Snowflake @@ -530,7 +533,7 @@ const setIcon = async (icon: string, table: TableType) => { MSSQL
- +
Snowflake diff --git a/packages/nc-gui/components/smartsheet/sidebar/RenameableMenuItem.vue b/packages/nc-gui/components/smartsheet/sidebar/RenameableMenuItem.vue index bed7376e4e..9de7d190eb 100644 --- a/packages/nc-gui/components/smartsheet/sidebar/RenameableMenuItem.vue +++ b/packages/nc-gui/components/smartsheet/sidebar/RenameableMenuItem.vue @@ -179,7 +179,7 @@ function onStopEdit() {
- +
{{ vModel.alias || vModel.title }} diff --git a/packages/nc-gui/composables/useGlobal/types.ts b/packages/nc-gui/composables/useGlobal/types.ts index 4969d406e8..8b4730c9f2 100644 --- a/packages/nc-gui/composables/useGlobal/types.ts +++ b/packages/nc-gui/composables/useGlobal/types.ts @@ -25,6 +25,7 @@ export interface AppInfo { teleEnabled: boolean type: string version: string + ee?: boolean } export interface StoredState { diff --git a/packages/nc-gui/pages/index/index/create-external.vue b/packages/nc-gui/pages/index/index/create-external.vue index 2cc6265336..568593ba5c 100644 --- a/packages/nc-gui/pages/index/index/create-external.vue +++ b/packages/nc-gui/pages/index/index/create-external.vue @@ -7,7 +7,7 @@ import { Form, Modal, SSLUsage, - clientTypes, + clientTypes as _clientTypes, computed, extractSdkResponseErrorMsg, fieldRequiredValidator, @@ -28,6 +28,8 @@ import { watch, } from '#imports' +const { appInfo } = useGlobal() + const useForm = Form.useForm const testSuccess = ref(false) @@ -64,7 +66,43 @@ const customFormState = ref({ extraParameters: [], }) +const clientTypes = computed(() => { + return _clientTypes.filter((type) => { + return appInfo.value?.ee || type.value !== ClientType.SNOWFLAKE + }) +}) + const validators = computed(() => { + let clientValidations: Record = { + 'dataSource.connection.host': [fieldRequiredValidator()], + 'dataSource.connection.port': [fieldRequiredValidator()], + 'dataSource.connection.user': [fieldRequiredValidator()], + 'dataSource.connection.password': [fieldRequiredValidator()], + 'dataSource.connection.database': [fieldRequiredValidator()], + } + + switch (formState.dataSource.client) { + case ClientType.SQLITE: + clientValidations = { + 'dataSource.connection.connection.filename': [fieldRequiredValidator()], + } + break + case ClientType.SNOWFLAKE: + clientValidations = { + 'dataSource.connection.account': [fieldRequiredValidator()], + 'dataSource.connection.username': [fieldRequiredValidator()], + 'dataSource.connection.password': [fieldRequiredValidator()], + 'dataSource.connection.warehouse': [fieldRequiredValidator()], + 'dataSource.connection.database': [fieldRequiredValidator()], + 'dataSource.connection.schema': [fieldRequiredValidator()], + } + break + case ClientType.PG: + case ClientType.MSSQL: + clientValidations['dataSource.searchPath.0'] = [fieldRequiredValidator()] + break + } + return { 'title': [ { @@ -75,31 +113,7 @@ const validators = computed(() => { ], 'extraParameters': [extraParameterValidator], 'dataSource.client': [fieldRequiredValidator()], - ...(formState.dataSource.client === ClientType.SQLITE - ? { - 'dataSource.connection.connection.filename': [fieldRequiredValidator()], - } - : formState.dataSource.client === ClientType.SNOWFLAKE - ? { - 'dataSource.connection.account': [fieldRequiredValidator()], - 'dataSource.connection.username': [fieldRequiredValidator()], - 'dataSource.connection.password': [fieldRequiredValidator()], - 'dataSource.connection.warehouse': [fieldRequiredValidator()], - 'dataSource.connection.database': [fieldRequiredValidator()], - 'dataSource.connection.schema': [fieldRequiredValidator()], - } - : { - 'dataSource.connection.host': [fieldRequiredValidator()], - 'dataSource.connection.port': [fieldRequiredValidator()], - 'dataSource.connection.user': [fieldRequiredValidator()], - 'dataSource.connection.password': [fieldRequiredValidator()], - 'dataSource.connection.database': [fieldRequiredValidator()], - ...([ClientType.PG, ClientType.MSSQL].includes(formState.dataSource.client) - ? { - 'dataSource.searchPath.0': [fieldRequiredValidator()], - } - : {}), - }), + ...clientValidations, } }) @@ -483,8 +497,10 @@ onMounted(async () => {
- - {{ opt }} + + {{ opt }} + @@ -526,14 +542,16 @@ onMounted(async () => { - + - +
@@ -547,7 +565,9 @@ onMounted(async () => {
-
+
+ +
diff --git a/packages/nocodb/src/lib/Noco.ts b/packages/nocodb/src/lib/Noco.ts index 0dc767c026..79bdc7fab5 100644 --- a/packages/nocodb/src/lib/Noco.ts +++ b/packages/nocodb/src/lib/Noco.ts @@ -16,7 +16,9 @@ import requestIp from 'request-ip'; import { v4 as uuidv4 } from 'uuid'; import { NcConfig } from '../interface/config'; +import { NC_LICENSE_KEY } from './constants'; import Migrator from './db/sql-migrator/lib/KnexMigrator'; +import Store from './models/Store'; import NcConfigFactory from './utils/NcConfigFactory'; import { Tele } from 'nc-help'; @@ -53,6 +55,7 @@ const NcProjectBuilder = process.env.EE export default class Noco { private static _this: Noco; + private static ee: boolean; public static get dashboardUrl(): string { let siteUrl = `http://localhost:${process.env.PORT || 8080}`; @@ -192,6 +195,7 @@ export default class Noco { } await Noco._ncMeta.metaInit(); + await Noco.loadEEState(); await this.initJwt(); await initAdminFromEnv(); @@ -542,4 +546,16 @@ export default class Noco { public static getConfig(): NcConfig { return Noco.config; } + + public static isEE(): boolean { + return Noco.ee; + } + + public static async loadEEState(): Promise { + try { + return (Noco.ee = !!(await Store.get(NC_LICENSE_KEY))); + } catch { + return (Noco.ee = false); + } + } } diff --git a/packages/nocodb/src/lib/db/sql-client/lib/SqlClientFactory.ts b/packages/nocodb/src/lib/db/sql-client/lib/SqlClientFactory.ts index 02c6798f56..e697867570 100644 --- a/packages/nocodb/src/lib/db/sql-client/lib/SqlClientFactory.ts +++ b/packages/nocodb/src/lib/db/sql-client/lib/SqlClientFactory.ts @@ -1,3 +1,5 @@ +import Noco from '../../../Noco'; +import SqlClientFactoryEE from './ee/SqlClientFactoryEE'; import MySqlClient from './mysql/MysqlClient'; import MssqlClient from './mssql/MssqlClient'; import OracleClient from './oracle/OracleClient'; @@ -6,10 +8,8 @@ import PgClient from './pg/PgClient'; import YugabyteClient from './pg/YugabyteClient'; import TidbClient from './mysql/TidbClient'; import VitessClient from './mysql/VitessClient'; -import SfClient from './snowflake/SnowflakeClient'; -import { SnowflakeClient } from 'nc-help'; -class SqlClientFactory { +export class SqlClientFactory { static create(connectionConfig) { connectionConfig.meta = connectionConfig.meta || {}; connectionConfig.pool = connectionConfig.pool || { min: 0, max: 5 }; @@ -33,13 +33,18 @@ class SqlClientFactory { if (connectionConfig.meta.dbtype === 'yugabyte') return new YugabyteClient(connectionConfig); return new PgClient(connectionConfig); - } else if (connectionConfig.client === 'snowflake') { - connectionConfig.client = SnowflakeClient; - return new SfClient(connectionConfig); } throw new Error('Database not supported'); } } -export default SqlClientFactory; +export default class { + static create(connectionConfig) { + if (Noco.isEE()) { + return SqlClientFactoryEE.create(connectionConfig); + } + + return SqlClientFactory.create(connectionConfig); + } +} diff --git a/packages/nocodb/src/lib/db/sql-client/lib/ee/SqlClientFactoryEE.ts b/packages/nocodb/src/lib/db/sql-client/lib/ee/SqlClientFactoryEE.ts new file mode 100644 index 0000000000..63df3a1221 --- /dev/null +++ b/packages/nocodb/src/lib/db/sql-client/lib/ee/SqlClientFactoryEE.ts @@ -0,0 +1,19 @@ +import { SqlClientFactory } from '../SqlClientFactory'; +import SfClient from '../snowflake/SnowflakeClient'; +import { SnowflakeClient } from 'nc-help'; + +class SqlClientFactoryEE { + static create(connectionConfig) { + connectionConfig.meta = connectionConfig.meta || {}; + connectionConfig.pool = connectionConfig.pool || { min: 0, max: 5 }; + connectionConfig.meta.dbtype = connectionConfig.meta.dbtype || ''; + + if (connectionConfig.client === 'snowflake') { + connectionConfig.client = SnowflakeClient; + return new SfClient(connectionConfig); + } + return SqlClientFactory.create(connectionConfig); + } +} + +export default SqlClientFactoryEE; diff --git a/packages/nocodb/src/lib/meta/api/utilApis.ts b/packages/nocodb/src/lib/meta/api/utilApis.ts index 16cee5adcb..c565289c46 100644 --- a/packages/nocodb/src/lib/meta/api/utilApis.ts +++ b/packages/nocodb/src/lib/meta/api/utilApis.ts @@ -3,7 +3,9 @@ import { Request, Response } from 'express'; import { compareVersions, validate } from 'compare-versions'; import { ViewTypes } from 'nocodb-sdk'; +import { NC_LICENSE_KEY } from '../../constants'; import Project from '../../models/Project'; +import Store from '../../models/Store'; import Noco from '../../Noco'; import NcConnectionMgrv2 from '../../utils/common/NcConnectionMgrv2'; import { MetaTable } from '../../utils/globals'; @@ -55,6 +57,7 @@ export async function appInfo(req: Request, res: Response) { ncMin: !!process.env.NC_MIN, teleEnabled: !process.env.NC_DISABLE_TELE, ncSiteUrl: (req as any).ncSiteUrl, + ee: !!(await Store.get(NC_LICENSE_KEY)), }; res.json(result); diff --git a/packages/nocodb/src/lib/migrations/v2/nc_013_sync_source.ts b/packages/nocodb/src/lib/migrations/v2/nc_013_sync_source.ts index 82e8e615d1..2110fe1ded 100644 --- a/packages/nocodb/src/lib/migrations/v2/nc_013_sync_source.ts +++ b/packages/nocodb/src/lib/migrations/v2/nc_013_sync_source.ts @@ -38,6 +38,7 @@ const up = async (knex: Knex) => { }; const down = async (knex) => { + await knex.schema.dropTable(MetaTable.SYNC_LOGS); await knex.schema.dropTable(MetaTable.SYNC_SOURCE); }; From d5644061e2cff507d665d677b5b13379cf10eea7 Mon Sep 17 00:00:00 2001 From: Pranav C Date: Mon, 26 Dec 2022 17:07:15 +0530 Subject: [PATCH 03/10] feat(gui): add embed option in shared view modal Signed-off-by: Pranav C #4680 --- .../smartsheet/toolbar/ShareView.vue | 26 +++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/packages/nc-gui/components/smartsheet/toolbar/ShareView.vue b/packages/nc-gui/components/smartsheet/toolbar/ShareView.vue index 0304f6a8fd..c3c7addd58 100644 --- a/packages/nc-gui/components/smartsheet/toolbar/ShareView.vue +++ b/packages/nc-gui/components/smartsheet/toolbar/ShareView.vue @@ -196,6 +196,21 @@ watch(passwordProtected, (value) => { const { locale } = useI18n() const isRtl = computed(() => isRtlLang(locale.value as any)) + +const iframeCode = computed(() => { + if (!sharedViewUrl.value) return + + return `