From 224a3bbdbf1cca656a9100a65b9f9e230a4ca7a5 Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Tue, 11 Apr 2023 16:44:00 +0800 Subject: [PATCH 01/21] feat(nocodb): include vultr hostname --- packages/nocodb/src/lib/plugins/vultr/index.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/nocodb/src/lib/plugins/vultr/index.ts b/packages/nocodb/src/lib/plugins/vultr/index.ts index 659b0263e6..2bf072c226 100644 --- a/packages/nocodb/src/lib/plugins/vultr/index.ts +++ b/packages/nocodb/src/lib/plugins/vultr/index.ts @@ -5,7 +5,7 @@ import type { XcPluginConfig } from 'nc-plugin'; const config: XcPluginConfig = { builder: VultrPlugin, title: 'Vultr Object Storage', - version: '0.0.1', + version: '0.0.2', logo: 'plugins/vultr.png', description: 'Using Vultr Object Storage can give flexibility and cloud storage that allows applications greater flexibility and access worldwide.', @@ -20,13 +20,13 @@ const config: XcPluginConfig = { type: XcType.SingleLineText, required: true, }, - // { - // key: 'region', - // label: 'Region', - // placeholder: 'Region', - // type: XcType.SingleLineText, - // required: true - // }, + { + key: 'hostname', + label: 'Host Name', + placeholder: 'e.g.: ewr1.vultrobjects.com', + type: XcType.SingleLineText, + required: true + }, { key: 'access_key', label: 'Access Key', From 81eec8833b3f299f6fa3ead3e4d497f2570e53eb Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Tue, 11 Apr 2023 16:44:17 +0800 Subject: [PATCH 02/21] fix(nocodb): s3 endpoint for vultr --- packages/nocodb/src/lib/plugins/vultr/Vultr.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/nocodb/src/lib/plugins/vultr/Vultr.ts b/packages/nocodb/src/lib/plugins/vultr/Vultr.ts index 422512a32f..dcc166bf64 100644 --- a/packages/nocodb/src/lib/plugins/vultr/Vultr.ts +++ b/packages/nocodb/src/lib/plugins/vultr/Vultr.ts @@ -105,9 +105,7 @@ export default class Vultr implements IStorageAdapterV2 { s3Options.accessKeyId = this.input.access_key; s3Options.secretAccessKey = this.input.access_secret; - s3Options.endpoint = new AWS.Endpoint( - `s3.${this.input.region}.cloud.ovh.net` - ); + s3Options.endpoint = new AWS.Endpoint(this.input.hostname); this.s3Client = new AWS.S3(s3Options); } From c98e53152b63db6ea381fa5b690901262830349b Mon Sep 17 00:00:00 2001 From: navi Date: Tue, 11 Apr 2023 15:13:19 +0100 Subject: [PATCH 03/21] New translations en.json (Chinese Simplified) --- packages/nc-gui/lang/zh-Hans.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/nc-gui/lang/zh-Hans.json b/packages/nc-gui/lang/zh-Hans.json index c8aec7fc76..1339d9ead6 100644 --- a/packages/nc-gui/lang/zh-Hans.json +++ b/packages/nc-gui/lang/zh-Hans.json @@ -221,7 +221,7 @@ "viewName": "查看名称", "viewLink": "查看链接", "columnName": "列名", - "columnToScanFor": "Column to scan", + "columnToScanFor": "要扫描的列", "columnType": "列类型", "roleName": "权限组", "roleDescription": "权限描述", @@ -412,8 +412,8 @@ "changePwd": "更改密码", "createView": "创建视图", "shareView": "分享视图", - "findRowByCodeScan": "Find row by scan", - "fillByCodeScan": "Fill by scan", + "findRowByCodeScan": "通过扫描查找行", + "fillByCodeScan": "通过扫描填充", "listSharedView": "共享视图列表", "ListView": "视图列表", "copyView": "复制视图", @@ -430,7 +430,7 @@ "iFrame": "复制可嵌入的 HTML 代码", "addWebhook": "添加新的 Webhook", "enableWebhook": "启用 Webhook", - "testWebhook": "Test Webhook", + "testWebhook": "测试Webhook", "copyWebhook": "复制 Webhook", "deleteWebhook": "删除 Webhook", "newToken": "添加新 Token", @@ -542,9 +542,9 @@ "orgViewer": "游客不能创建新项目,仅允许访问受邀项目。" }, "codeScanner": { - "loadingScanner": "Loading the scanner...", + "loadingScanner": "正在加载扫描仪...", "selectColumn": "Select a column (QR code or Barcode) that you want to use for finding a row by scanning.", - "moreThanOneRowFoundForCode": "More than one row found for this code. Currently only unique codes are supported.", + "moreThanOneRowFoundForCode": "找到了多行此代码。目前只支持唯一的代码。", "noRowFoundForCode": "所选列没有找到此代码行" }, "map": { From 84fb1d5de2ec4293c98a43b34f9602f362ce5458 Mon Sep 17 00:00:00 2001 From: navi Date: Wed, 12 Apr 2023 03:39:51 +0100 Subject: [PATCH 04/21] New translations en.json (Chinese Simplified) --- packages/nc-gui/lang/zh-Hans.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/nc-gui/lang/zh-Hans.json b/packages/nc-gui/lang/zh-Hans.json index 1339d9ead6..03738dc710 100644 --- a/packages/nc-gui/lang/zh-Hans.json +++ b/packages/nc-gui/lang/zh-Hans.json @@ -470,7 +470,7 @@ "addOrEditStack": "添加/编辑分类标签" }, "map": { - "mappedBy": "Mapped By", + "mappedBy": "映射字段", "chooseMappingField": "选择映射字段", "openInGoogleMaps": "谷歌地图", "openInOpenStreetMap": "OSM" @@ -543,14 +543,14 @@ }, "codeScanner": { "loadingScanner": "正在加载扫描仪...", - "selectColumn": "Select a column (QR code or Barcode) that you want to use for finding a row by scanning.", + "selectColumn": "选择要用于扫描查找行的列(二维码或条形码)。", "moreThanOneRowFoundForCode": "找到了多行此代码。目前只支持唯一的代码。", "noRowFoundForCode": "所选列没有找到此代码行" }, "map": { "overLimit": "你已经超出了限制。", "closeLimit": "您已接近上限。", - "limitNumber": "The limit of markers shown in a Map View is 1000 records." + "limitNumber": "在地图视图中显示的标记的限制是1000条记录。" }, "footerInfo": "每页行驶", "upload": "选择文件以上传", From dc5ae370f4a957cd33bf439143b5a519e944970f Mon Sep 17 00:00:00 2001 From: Khisby Al Ghofari Date: Wed, 12 Apr 2023 13:10:42 +0700 Subject: [PATCH 05/21] feat: add check all on action column editor import modal --- packages/nc-gui/components/template/Editor.vue | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/packages/nc-gui/components/template/Editor.vue b/packages/nc-gui/components/template/Editor.vue index 214ce1da20..4de89e1090 100644 --- a/packages/nc-gui/components/template/Editor.vue +++ b/packages/nc-gui/components/template/Editor.vue @@ -87,6 +87,8 @@ const isImporting = ref(false) const importingTips = ref>({}) +const checkAllRecord = ref(false) + const uiTypeOptions = ref( (Object.keys(UITypes) as (keyof typeof UITypes)[]) .filter( @@ -615,6 +617,13 @@ function handleEditableTnChange(idx: number) { function isSelectDisabled(uidt: string, disableSelect = false) { return (uidt === UITypes.SingleSelect || uidt === UITypes.MultiSelect) && disableSelect } + +function handleCheckAllRecord(event, table_name){ + const isChecked = event.target.checked; + for (const record of srcDestMapping.value[table_name]) { + record.enabled = isChecked; + } +} From 348e6a696436ebe14090473d53ce698d9dac345b Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Wed, 12 Apr 2023 18:34:57 +0800 Subject: [PATCH 08/21] fix(nocodb): add missing parsing logic --- .../db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts index 2890fd3508..453af0f141 100644 --- a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts +++ b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts @@ -3242,17 +3242,24 @@ function extractCondition(nestedArrayConditions, aliasColObjMap) { // eslint-disable-next-line prefer-const let [logicOp, alias, op, value] = str.match(/(?:~(and|or|not))?\((.*?),(\w+),(.*)\)/)?.slice(1) || []; + + if (!alias && !op && !value) { + // try match with blank filter format + [logicOp, alias, op, value] = + str.match(/(?:~(and|or|not))?\((.*?),(\w+)\)/)?.slice(1) || []; + } let sub_op = null; if (aliasColObjMap[alias]) { if ( [UITypes.Date, UITypes.DateTime].includes(aliasColObjMap[alias].uidt) ) { - value = value.split(','); + value = value?.split(','); // the first element would be sub_op - sub_op = value[0]; + sub_op = value?.[0]; // remove the first element which is sub_op - value.shift(); + value?.shift(); + value = value?.[0]; } else if (op === 'in') { value = value.split(','); } From 1dc832b0bfaf3375660db1af652b8fc55d152362 Mon Sep 17 00:00:00 2001 From: Khisby Al Ghofari Date: Wed, 12 Apr 2023 17:53:01 +0700 Subject: [PATCH 09/21] feat(nc-gui): specific param type --- packages/nc-gui/components/template/Editor.vue | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/nc-gui/components/template/Editor.vue b/packages/nc-gui/components/template/Editor.vue index ca19059af6..6af851e630 100644 --- a/packages/nc-gui/components/template/Editor.vue +++ b/packages/nc-gui/components/template/Editor.vue @@ -32,6 +32,7 @@ import { useTabs, } from '#imports' import { TabType } from '~/lib' +import type { CheckboxChangeEvent } from 'ant-design-vue/es/checkbox/interface' const { quickImportType, projectTemplate, importData, importColumns, importDataOnly, maxRowsToParse, baseId } = defineProps() @@ -173,7 +174,7 @@ const prevEditableTn = ref([]) onMounted(() => { parseAndLoadTemplate() - + // used to record the previous EditableTn values // for checking the table duplication in current import // and updating the key in importData @@ -618,9 +619,9 @@ function isSelectDisabled(uidt: string, disableSelect = false) { return (uidt === UITypes.SingleSelect || uidt === UITypes.MultiSelect) && disableSelect } -function handleCheckAllRecord(event, table_name) { +function handleCheckAllRecord(event: CheckboxChangeEvent, tableName: string) { const isChecked = event.target.checked - for (const record of srcDestMapping.value[table_name]) { + for (const record of srcDestMapping.value[tableName]) { record.enabled = isChecked } } From 7fecf73556188394e001cb10f98582a90855700e Mon Sep 17 00:00:00 2001 From: Khisby Al Ghofari Date: Wed, 12 Apr 2023 17:54:23 +0700 Subject: [PATCH 10/21] feat(nc-gui): lint --- packages/nc-gui/components/template/Editor.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/nc-gui/components/template/Editor.vue b/packages/nc-gui/components/template/Editor.vue index 6af851e630..455611e3a7 100644 --- a/packages/nc-gui/components/template/Editor.vue +++ b/packages/nc-gui/components/template/Editor.vue @@ -3,6 +3,7 @@ import dayjs from 'dayjs' import utc from 'dayjs/plugin/utc' import type { ColumnType, TableType } from 'nocodb-sdk' import { UITypes, isSystemColumn, isVirtualCol } from 'nocodb-sdk' +import type { CheckboxChangeEvent } from 'ant-design-vue/es/checkbox/interface' import { srcDestMappingColumns, tableColumns } from './utils' import { Empty, @@ -32,7 +33,6 @@ import { useTabs, } from '#imports' import { TabType } from '~/lib' -import type { CheckboxChangeEvent } from 'ant-design-vue/es/checkbox/interface' const { quickImportType, projectTemplate, importData, importColumns, importDataOnly, maxRowsToParse, baseId } = defineProps() From 5036a5d27e752ac69f084e9f84fc2b3aca8ee771 Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Wed, 12 Apr 2023 20:33:56 +0800 Subject: [PATCH 11/21] fix(nc-gui): remove non-existing sign out api --- packages/nc-gui/composables/useGlobal/actions.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/nc-gui/composables/useGlobal/actions.ts b/packages/nc-gui/composables/useGlobal/actions.ts index b08ec5989d..3190f7dbde 100644 --- a/packages/nc-gui/composables/useGlobal/actions.ts +++ b/packages/nc-gui/composables/useGlobal/actions.ts @@ -10,10 +10,6 @@ export function useGlobalActions(state: State): Actions { const signOut: Actions['signOut'] = async () => { state.token.value = null state.user.value = null - try { - const nuxtApp = useNuxtApp() - await nuxtApp.$api.auth.signout() - } catch {} } /** Sign in by setting the token in localStorage */ From 625cb7c6bbc69f65a21e2f8fb00fd205c436213a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 12 Apr 2023 21:21:29 +0000 Subject: [PATCH 12/21] chore(deps): bump vm2 from 3.9.15 to 3.9.16 in /packages/nocodb Bumps [vm2](https://github.com/patriksimek/vm2) from 3.9.15 to 3.9.16. - [Release notes](https://github.com/patriksimek/vm2/releases) - [Changelog](https://github.com/patriksimek/vm2/blob/master/CHANGELOG.md) - [Commits](https://github.com/patriksimek/vm2/compare/3.9.15...3.9.16) --- updated-dependencies: - dependency-name: vm2 dependency-type: indirect ... Signed-off-by: dependabot[bot] --- packages/nocodb/package-lock.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/nocodb/package-lock.json b/packages/nocodb/package-lock.json index 03e968567c..a9243323a7 100644 --- a/packages/nocodb/package-lock.json +++ b/packages/nocodb/package-lock.json @@ -17364,9 +17364,9 @@ "dev": true }, "node_modules/vm2": { - "version": "3.9.15", - "resolved": "https://registry.npmjs.org/vm2/-/vm2-3.9.15.tgz", - "integrity": "sha512-XqNqknHGw2avJo13gbIwLNZUumvrSHc9mLqoadFZTpo3KaNEJoe1I0lqTFhRXmXD7WkLyG01aaraXdXT0pa4ag==", + "version": "3.9.16", + "resolved": "https://registry.npmjs.org/vm2/-/vm2-3.9.16.tgz", + "integrity": "sha512-3T9LscojNTxdOyG+e8gFeyBXkMlOBYDoF6dqZbj+MPVHi9x10UfiTAJIobuchRCp3QvC+inybTbMJIUrLsig0w==", "dependencies": { "acorn": "^8.7.0", "acorn-walk": "^8.2.0" @@ -32786,9 +32786,9 @@ "dev": true }, "vm2": { - "version": "3.9.15", - "resolved": "https://registry.npmjs.org/vm2/-/vm2-3.9.15.tgz", - "integrity": "sha512-XqNqknHGw2avJo13gbIwLNZUumvrSHc9mLqoadFZTpo3KaNEJoe1I0lqTFhRXmXD7WkLyG01aaraXdXT0pa4ag==", + "version": "3.9.16", + "resolved": "https://registry.npmjs.org/vm2/-/vm2-3.9.16.tgz", + "integrity": "sha512-3T9LscojNTxdOyG+e8gFeyBXkMlOBYDoF6dqZbj+MPVHi9x10UfiTAJIobuchRCp3QvC+inybTbMJIUrLsig0w==", "requires": { "acorn": "^8.7.0", "acorn-walk": "^8.2.0" From 000a39f19dfe12114e86210f418720c986b1b564 Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Thu, 13 Apr 2023 13:02:43 +0800 Subject: [PATCH 13/21] fix(nc-gui): add back signout api --- packages/nc-gui/composables/useGlobal/actions.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/nc-gui/composables/useGlobal/actions.ts b/packages/nc-gui/composables/useGlobal/actions.ts index 3190f7dbde..bfb6e3ad65 100644 --- a/packages/nc-gui/composables/useGlobal/actions.ts +++ b/packages/nc-gui/composables/useGlobal/actions.ts @@ -10,6 +10,10 @@ export function useGlobalActions(state: State): Actions { const signOut: Actions['signOut'] = async () => { state.token.value = null state.user.value = null + try { + const nuxtApp = useNuxtApp() + await nuxtApp.$api.auth.signout() + } catch {} } /** Sign in by setting the token in localStorage */ @@ -46,7 +50,7 @@ export function useGlobalActions(state: State): Actions { message.error(err.message || t('msg.error.youHaveBeenSignedOut')) await signOut() }) - .finally(() => resolve()) + .finally(() => resolve(true)) }) } From d60db3d7bbd3f8587aad8c56268256010c75ab07 Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Thu, 13 Apr 2023 13:03:11 +0800 Subject: [PATCH 14/21] fix(nocodb): add signout function to clear refresh token --- .../nocodb/src/lib/controllers/user/user.ctl.ts | 10 ++++++++++ packages/nocodb/src/lib/services/user/index.ts | 15 +++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/packages/nocodb/src/lib/controllers/user/user.ctl.ts b/packages/nocodb/src/lib/controllers/user/user.ctl.ts index c68ada72f7..6b4fee6bc9 100644 --- a/packages/nocodb/src/lib/controllers/user/user.ctl.ts +++ b/packages/nocodb/src/lib/controllers/user/user.ctl.ts @@ -98,6 +98,15 @@ async function signin(req, res, next) { )(req, res, next); } +async function signout(req: Request, res): Promise { + res.json( + await userService.signout({ + req, + res, + }) + ); +} + async function googleSignin(req, res, next) { passport.authenticate( 'google', @@ -246,6 +255,7 @@ const mapRoutes = (router) => { // new API router.post('/api/v1/auth/user/signup', catchError(signup)); router.post('/api/v1/auth/user/signin', catchError(signin)); + router.post('/api/v1/auth/user/signout', catchError(signout)); router.get( '/api/v1/auth/user/me', extractProjectIdAndAuthenticate, diff --git a/packages/nocodb/src/lib/services/user/index.ts b/packages/nocodb/src/lib/services/user/index.ts index 1afa86648e..508b35a1cd 100644 --- a/packages/nocodb/src/lib/services/user/index.ts +++ b/packages/nocodb/src/lib/services/user/index.ts @@ -458,5 +458,20 @@ export async function signup(param: { } as any; } +export async function signout(param: { req: any; res: any }): Promise { + try { + param.res.clearCookie('refresh_token'); + const user = (param.req as any).user; + if (user) { + await User.update(user.id, { + refresh_token: null, + }); + } + return { msg: 'Signed out successfully' }; + } catch (e) { + NcError.badRequest(e.message); + } +} + export * from './helpers'; export { default as initAdminFromEnv } from './initAdminFromEnv'; From efb58e8d31f08cd0c7f7e2d2ed724fee51845c56 Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Thu, 13 Apr 2023 13:57:16 +0800 Subject: [PATCH 15/21] feat(nocodb): add convertDateFormat --- .../lib/sql/helpers/convertDateFormat.ts | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/helpers/convertDateFormat.ts diff --git a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/helpers/convertDateFormat.ts b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/helpers/convertDateFormat.ts new file mode 100644 index 0000000000..c9e833e3b3 --- /dev/null +++ b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/helpers/convertDateFormat.ts @@ -0,0 +1,23 @@ +export function convertDateFormat(date_format: string, type: string) { + if (date_format === 'YYYY-MM-DD') { + if (type === 'mysql2' || type === 'sqlite') return '%Y-%m-%d'; + } else if (date_format === 'YYYY/MM/DD') { + if (type === 'mysql2' || type === 'sqlite') return '%Y/%m/%d'; + } else if (date_format === 'DD-MM-YYYY') { + if (type === 'mysql2' || type === 'sqlite') return '%d/%m/%Y'; + } else if (date_format === 'MM-DD-YYYY') { + if (type === 'mysql2' || type === 'sqlite') return '%d-%m-%Y'; + } else if (date_format === 'DD/MM/YYYY') { + if (type === 'mysql2' || type === 'sqlite') return '%d/%m/%Y'; + } else if (date_format === 'MM/DD/YYYY') { + if (type === 'mysql2' || type === 'sqlite') return '%m-%d-%Y'; + } else if (date_format === 'DD MM YYYY') { + if (type === 'mysql2' || type === 'sqlite') return '%d %m %Y'; + } else if (date_format === 'MM DD YYYY') { + if (type === 'mysql2' || type === 'sqlite') return '%m %d %Y'; + } else if (date_format === 'YYYY MM DD') { + if (type === 'mysql2' || type === 'sqlite') return '%Y %m %d'; + } + // pg / mssql + return date_format; +} From 64e24b12159ed13128b9a057c92f40c612761b3b Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Thu, 13 Apr 2023 13:57:48 +0800 Subject: [PATCH 16/21] fix(nocodb): convert date format based on meta in CONCAT --- .../sql/formulav2/formulaQueryBuilderv2.ts | 39 ++++++++++++++++++- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/formulav2/formulaQueryBuilderv2.ts b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/formulav2/formulaQueryBuilderv2.ts index f6a93ea247..7a660bf2b0 100644 --- a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/formulav2/formulaQueryBuilderv2.ts +++ b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/formulav2/formulaQueryBuilderv2.ts @@ -6,8 +6,9 @@ import FormulaColumn from '../../../../../models/FormulaColumn'; import { validateDateWithUnknownFormat } from '../helpers/formulaFnHelper'; import { CacheGetType, CacheScope } from '../../../../../utils/globals'; import NocoCache from '../../../../../cache/NocoCache'; +import Column from '../../../../../models/Column'; +import { convertDateFormat } from '../helpers/convertDateFormat'; import type Model from '../../../../../models/Model'; -import type Column from '../../../../../models/Column'; import type RollupColumn from '../../../../../models/RollupColumn'; import type { XKnex } from '../../../index'; import type LinkToAnotherRecordColumn from '../../../../../models/LinkToAnotherRecordColumn'; @@ -633,8 +634,42 @@ async function _formulaQueryBuilder( `${pt.callee.name}(${( await Promise.all( pt.arguments.map(async (arg) => { - const query = (await fn(arg)).builder.toQuery(); + let query = (await fn(arg)).builder.toQuery(); if (pt.callee.name === 'CONCAT') { + if ( + arg.type === 'Identifier' && + arg.name in columnIdToUidt && + columnIdToUidt[arg.name] === UITypes.Date + ) { + const meta = ( + await Column.get({ + colId: arg.name, + }) + ).meta; + + if (knex.clientType() === 'mysql2') { + query = `DATE_FORMAT(${query}, '${convertDateFormat( + meta.date_format, + knex.clientType() + )}')`; + } else if (knex.clientType() === 'pg') { + query = `TO_CHAR(${query}, '${convertDateFormat( + meta.date_format, + knex.clientType() + )}')`; + } else if (knex.clientType() === 'sqlite') { + query = `strftime('${convertDateFormat( + meta.date_format, + knex.clientType() + )}', ${query})`; + } else if (knex.clientType() === 'mssql') { + query = `FORMAT(${query}, '${convertDateFormat( + meta.date_format, + knex.clientType() + )}')`; + } + } + if (knex.clientType() === 'mysql2') { // mysql2: CONCAT() returns NULL if any argument is NULL. // adding IFNULL to convert NULL values to empty strings From 02fd36589d1d446d9ca5c2ed5cb33802a1fa09ae Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Thu, 13 Apr 2023 16:30:00 +0800 Subject: [PATCH 17/21] fix(nocodb): sqlite -> sqlite3 --- .../lib/sql/helpers/convertDateFormat.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/helpers/convertDateFormat.ts b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/helpers/convertDateFormat.ts index c9e833e3b3..97057840f3 100644 --- a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/helpers/convertDateFormat.ts +++ b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/helpers/convertDateFormat.ts @@ -1,22 +1,22 @@ export function convertDateFormat(date_format: string, type: string) { if (date_format === 'YYYY-MM-DD') { - if (type === 'mysql2' || type === 'sqlite') return '%Y-%m-%d'; + if (type === 'mysql2' || type === 'sqlite3') return '%Y-%m-%d'; } else if (date_format === 'YYYY/MM/DD') { - if (type === 'mysql2' || type === 'sqlite') return '%Y/%m/%d'; + if (type === 'mysql2' || type === 'sqlite3') return '%Y/%m/%d'; } else if (date_format === 'DD-MM-YYYY') { - if (type === 'mysql2' || type === 'sqlite') return '%d/%m/%Y'; + if (type === 'mysql2' || type === 'sqlite3') return '%d/%m/%Y'; } else if (date_format === 'MM-DD-YYYY') { - if (type === 'mysql2' || type === 'sqlite') return '%d-%m-%Y'; + if (type === 'mysql2' || type === 'sqlite3') return '%d-%m-%Y'; } else if (date_format === 'DD/MM/YYYY') { - if (type === 'mysql2' || type === 'sqlite') return '%d/%m/%Y'; + if (type === 'mysql2' || type === 'sqlite3') return '%d/%m/%Y'; } else if (date_format === 'MM/DD/YYYY') { - if (type === 'mysql2' || type === 'sqlite') return '%m-%d-%Y'; + if (type === 'mysql2' || type === 'sqlite3') return '%m-%d-%Y'; } else if (date_format === 'DD MM YYYY') { - if (type === 'mysql2' || type === 'sqlite') return '%d %m %Y'; + if (type === 'mysql2' || type === 'sqlite3') return '%d %m %Y'; } else if (date_format === 'MM DD YYYY') { - if (type === 'mysql2' || type === 'sqlite') return '%m %d %Y'; + if (type === 'mysql2' || type === 'sqlite3') return '%m %d %Y'; } else if (date_format === 'YYYY MM DD') { - if (type === 'mysql2' || type === 'sqlite') return '%Y %m %d'; + if (type === 'mysql2' || type === 'sqlite3') return '%Y %m %d'; } // pg / mssql return date_format; From 841a57cfcf57e882dbdbf31204273895c56e4551 Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Thu, 13 Apr 2023 16:30:10 +0800 Subject: [PATCH 18/21] feat(nocodb): add convertDateFormatForConcat --- .../lib/sql/helpers/formulaFnHelper.ts | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/helpers/formulaFnHelper.ts b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/helpers/formulaFnHelper.ts index e3268d7406..5a21ba3261 100644 --- a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/helpers/formulaFnHelper.ts +++ b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/helpers/formulaFnHelper.ts @@ -1,5 +1,8 @@ import dayjs, { extend } from 'dayjs'; import customParseFormat from 'dayjs/plugin/customParseFormat.js'; +import { UITypes } from 'nocodb-sdk'; +import Column from '../../../../../models/Column'; +import { convertDateFormat } from './convertDateFormat'; extend(customParseFormat); export function getWeekdayByText(v: string) { @@ -50,3 +53,45 @@ export function validateDateWithUnknownFormat(v: string) { } return false; } + +export async function convertDateFormatForConcat( + o, + columnIdToUidt, + query, + clientType +) { + if ( + o?.type === 'Identifier' && + o?.name in columnIdToUidt && + columnIdToUidt[o.name] === UITypes.Date + ) { + const meta = ( + await Column.get({ + colId: o.name, + }) + ).meta; + + if (clientType === 'mysql2') { + query = `DATE_FORMAT(${query}, '${convertDateFormat( + meta.date_format, + clientType + )}')`; + } else if (clientType === 'pg') { + query = `TO_CHAR(${query}, '${convertDateFormat( + meta.date_format, + clientType + )}')`; + } else if (clientType === 'sqlite3') { + query = `strftime('${convertDateFormat( + meta.date_format, + clientType + )}', ${query})`; + } else if (clientType === 'mssql') { + query = `FORMAT(${query}, '${convertDateFormat( + meta.date_format, + clientType + )}')`; + } + } + return query; +} From 133de6d7925752a6947e310433437410b0e0e824 Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Thu, 13 Apr 2023 16:30:29 +0800 Subject: [PATCH 19/21] refactor(nocodb): use convertDateFormatForConcat & fix sqlite case --- .../sql/formulav2/formulaQueryBuilderv2.ts | 69 +++++++++---------- 1 file changed, 31 insertions(+), 38 deletions(-) diff --git a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/formulav2/formulaQueryBuilderv2.ts b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/formulav2/formulaQueryBuilderv2.ts index 7a660bf2b0..1ee8c93268 100644 --- a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/formulav2/formulaQueryBuilderv2.ts +++ b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/formulav2/formulaQueryBuilderv2.ts @@ -3,11 +3,13 @@ import { jsepCurlyHook, UITypes } from 'nocodb-sdk'; import mapFunctionName from '../mapFunctionName'; import genRollupSelectv2 from '../genRollupSelectv2'; import FormulaColumn from '../../../../../models/FormulaColumn'; -import { validateDateWithUnknownFormat } from '../helpers/formulaFnHelper'; +import { + convertDateFormatForConcat, + validateDateWithUnknownFormat, +} from '../helpers/formulaFnHelper'; import { CacheGetType, CacheScope } from '../../../../../utils/globals'; import NocoCache from '../../../../../cache/NocoCache'; -import Column from '../../../../../models/Column'; -import { convertDateFormat } from '../helpers/convertDateFormat'; +import type Column from '../../../../../models/Column'; import type Model from '../../../../../models/Model'; import type RollupColumn from '../../../../../models/RollupColumn'; import type { XKnex } from '../../../index'; @@ -636,38 +638,15 @@ async function _formulaQueryBuilder( pt.arguments.map(async (arg) => { let query = (await fn(arg)).builder.toQuery(); if (pt.callee.name === 'CONCAT') { - if ( - arg.type === 'Identifier' && - arg.name in columnIdToUidt && - columnIdToUidt[arg.name] === UITypes.Date - ) { - const meta = ( - await Column.get({ - colId: arg.name, - }) - ).meta; - - if (knex.clientType() === 'mysql2') { - query = `DATE_FORMAT(${query}, '${convertDateFormat( - meta.date_format, - knex.clientType() - )}')`; - } else if (knex.clientType() === 'pg') { - query = `TO_CHAR(${query}, '${convertDateFormat( - meta.date_format, - knex.clientType() - )}')`; - } else if (knex.clientType() === 'sqlite') { - query = `strftime('${convertDateFormat( - meta.date_format, - knex.clientType() - )}', ${query})`; - } else if (knex.clientType() === 'mssql') { - query = `FORMAT(${query}, '${convertDateFormat( - meta.date_format, - knex.clientType() - )}')`; - } + if (knex.clientType() !== 'sqlite3') { + query = await convertDateFormatForConcat( + arg, + columnIdToUidt, + query, + knex.clientType() + ); + } else { + // sqlite3: special handling - See BinaryExpression } if (knex.clientType() === 'mysql2') { @@ -714,8 +693,8 @@ async function _formulaQueryBuilder( pt.left.fnName = pt.left.fnName || 'ARITH'; pt.right.fnName = pt.right.fnName || 'ARITH'; - const left = (await fn(pt.left, null, pt.operator)).builder.toQuery(); - const right = (await fn(pt.right, null, pt.operator)).builder.toQuery(); + let left = (await fn(pt.left, null, pt.operator)).builder.toQuery(); + let right = (await fn(pt.right, null, pt.operator)).builder.toQuery(); let sql = `${left} ${pt.operator} ${right}${colAlias}`; // comparing a date with empty string would throw @@ -759,8 +738,22 @@ async function _formulaQueryBuilder( } } - // handle NULL values when calling CONCAT for sqlite3 if (pt.left.fnName === 'CONCAT' && knex.clientType() === 'sqlite3') { + // handle date format + left = await convertDateFormatForConcat( + pt.left?.arguments?.[0], + columnIdToUidt, + left, + knex.clientType() + ); + right = await convertDateFormatForConcat( + pt.right?.arguments?.[0], + columnIdToUidt, + right, + knex.clientType() + ); + + // handle NULL values when calling CONCAT for sqlite3 sql = `COALESCE(${left}, '') ${pt.operator} COALESCE(${right},'')${colAlias}`; } From 5bc2c389a610ab31548bba0cd6d279ee94f3e772 Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Thu, 13 Apr 2023 17:22:10 +0800 Subject: [PATCH 20/21] fix(nc-gui): revise signout logic in refreshToken --- packages/nc-gui/composables/useGlobal/actions.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/nc-gui/composables/useGlobal/actions.ts b/packages/nc-gui/composables/useGlobal/actions.ts index bfb6e3ad65..8b62ac9ead 100644 --- a/packages/nc-gui/composables/useGlobal/actions.ts +++ b/packages/nc-gui/composables/useGlobal/actions.ts @@ -46,9 +46,11 @@ export function useGlobalActions(state: State): Actions { signIn(response.data.token) } }) - .catch(async (err) => { - message.error(err.message || t('msg.error.youHaveBeenSignedOut')) - await signOut() + .catch(async () => { + if (state.token.value && state.user.value) { + await signOut() + message.error(t('msg.error.youHaveBeenSignedOut')) + } }) .finally(() => resolve(true)) }) From f2002f2310bfeae3f289a42859a69cce6692115c Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Thu, 13 Apr 2023 18:55:15 +0800 Subject: [PATCH 21/21] fix(nocodb): search formula in pg.ts --- .../lib/db/sql-data-mapper/lib/sql/functionMappings/pg.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/pg.ts b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/pg.ts index 222b0751bc..50fd306e94 100644 --- a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/pg.ts +++ b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/pg.ts @@ -17,9 +17,9 @@ const pg = { builder: args.knex.raw( `POSITION(${args.knex.raw( (await args.fn(args.pt.arguments[1])).builder.toQuery() - )} in ${args.knex - .raw((await args.fn(args.pt.arguments[0])).builder) - .toQuery()})${args.colAlias}` + )} in ${args.knex.raw( + (await args.fn(args.pt.arguments[0])).builder.toQuery() + )})${args.colAlias}` ), }; },