From 02854a9e41584e2990553a130fd0a04ad67e8f5f Mon Sep 17 00:00:00 2001 From: Pranav C Date: Thu, 19 Jan 2023 10:49:50 +0530 Subject: [PATCH 01/27] fix(api): mssql - alter column query correction Signed-off-by: Pranav C --- .../nocodb/src/lib/db/sql-client/lib/mssql/MssqlClient.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/nocodb/src/lib/db/sql-client/lib/mssql/MssqlClient.ts b/packages/nocodb/src/lib/db/sql-client/lib/mssql/MssqlClient.ts index 27feafb56b..962ae5eca8 100644 --- a/packages/nocodb/src/lib/db/sql-client/lib/mssql/MssqlClient.ts +++ b/packages/nocodb/src/lib/db/sql-client/lib/mssql/MssqlClient.ts @@ -2631,7 +2631,7 @@ class MssqlClient extends KnexClient { if (n.dtxp !== o.dtxp && !['text'].includes(n.dt)) { query += this.genQuery( - `\nALTER TABLE ?? ALTER COLUMN ?? ${n.dt}(${n.dtxp});\n`, + `\nALTER TABLE ?? ALTER COLUMN ?? ${n.dt}${!getDefaultLengthIsDisabled(n.dt) && n.dtxp ? `(${n.dtxp})` : ''};\n`, [this.getTnPath(t), n.cn], shouldSanitize ); @@ -2797,9 +2797,6 @@ function getDefaultLengthIsDisabled(type) { // case 'sysname': case 'bigint': case 'bit': - case 'date': - case 'datetime': - case 'datetime2': case 'datetimeoffset': case 'decimal': case 'float': @@ -2824,6 +2821,9 @@ function getDefaultLengthIsDisabled(type) { return true; break; default: + case 'date': + case 'datetime': + case 'datetime2': case 'varchar': return false; break; From 16d686593f36064ee6ae4e7afc5911edc2625706 Mon Sep 17 00:00:00 2001 From: Pranav C Date: Thu, 19 Jan 2023 13:30:41 +0530 Subject: [PATCH 02/27] chore(action): bring back executable build in nightly dev release Signed-off-by: Pranav C --- .github/workflows/release-nightly-dev.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/release-nightly-dev.yml b/.github/workflows/release-nightly-dev.yml index 30bd16e41e..e4a66f71ce 100644 --- a/.github/workflows/release-nightly-dev.yml +++ b/.github/workflows/release-nightly-dev.yml @@ -54,13 +54,13 @@ jobs: NPM_TOKEN: "${{ secrets.NPM_TOKEN }}" # Build executables and publish to GitHub - # release-executables: - # needs: [set-tag, release-npm] - # uses: ./.github/workflows/release-timely-executables.yml - # with: - # tag: ${{ needs.set-tag.outputs.current_version }}-${{ needs.set-tag.outputs.nightly_build_tag }} - # secrets: - # NC_GITHUB_TOKEN: "${{ secrets.NC_GITHUB_TOKEN }}" + release-executables: + needs: [set-tag, release-npm] + uses: ./.github/workflows/release-timely-executables.yml + with: + tag: ${{ needs.set-tag.outputs.current_version }}-${{ needs.set-tag.outputs.nightly_build_tag }} + secrets: + NC_GITHUB_TOKEN: "${{ secrets.NC_GITHUB_TOKEN }}" # Build docker image and push to docker hub release-docker: From 0839d3d171f0598baf43af851344a509e26e405e Mon Sep 17 00:00:00 2001 From: Pranav C Date: Thu, 19 Jan 2023 15:11:08 +0530 Subject: [PATCH 03/27] fix(api): mssql - column alter query correction Signed-off-by: Pranav C --- packages/nocodb-sdk/src/lib/sqlUi/MssqlUi.ts | 116 ------------------ .../db/sql-client/lib/mssql/MssqlClient.ts | 45 +------ 2 files changed, 4 insertions(+), 157 deletions(-) diff --git a/packages/nocodb-sdk/src/lib/sqlUi/MssqlUi.ts b/packages/nocodb-sdk/src/lib/sqlUi/MssqlUi.ts index c958eae2ba..7762be3c4a 100644 --- a/packages/nocodb-sdk/src/lib/sqlUi/MssqlUi.ts +++ b/packages/nocodb-sdk/src/lib/sqlUi/MssqlUi.ts @@ -163,122 +163,6 @@ export class MssqlUi { }; } - // static getDefaultLengthForDatatype(type) { - // switch (type) { - // case "int": - // return 11; - // break; - // case "tinyint": - // return 1; - // break; - // case "smallint": - // return 5; - // break; - // - // case "mediumint": - // return 9; - // break; - // case "bigint": - // return 20; - // break; - // case "bit": - // return 64; - // break; - // case "boolean": - // return ''; - // break; - // case "float": - // return 12; - // break; - // case "decimal": - // return 10; - // break; - // case "double": - // return 22; - // break; - // case "serial": - // return 20; - // break; - // case "date": - // return ''; - // break; - // case "datetime": - // case "timestamp": - // return 6; - // break; - // case "time": - // return ''; - // break; - // case "year": - // return ''; - // break; - // case "char": - // return 255; - // break; - // case "varchar": - // return 45; - // break; - // case "nchar": - // return 255; - // break; - // case "text": - // return ''; - // break; - // case "tinytext": - // return ''; - // break; - // case "mediumtext": - // return ''; - // break; - // case "longtext": - // return '' - // break; - // case "binary": - // return 255; - // break; - // case "varbinary": - // return 65500; - // break; - // case "blob": - // return ''; - // break; - // case "tinyblob": - // return ''; - // break; - // case "mediumblob": - // return ''; - // break; - // case "longblob": - // return ''; - // break; - // case "enum": - // return '\'a\',\'b\''; - // break; - // case "set": - // return '\'a\',\'b\''; - // break; - // case "geometry": - // return ''; - // case "point": - // return ''; - // case "linestring": - // return ''; - // case "polygon": - // return ''; - // case "multipoint": - // return ''; - // case "multilinestring": - // return ''; - // case "multipolygon": - // return ''; - // case "json": - // return '' - // break; - // - // } - // - // } - static getDefaultLengthForDatatype(type) { switch (type) { case 'bigint': diff --git a/packages/nocodb/src/lib/db/sql-client/lib/mssql/MssqlClient.ts b/packages/nocodb/src/lib/db/sql-client/lib/mssql/MssqlClient.ts index 962ae5eca8..0f84e04461 100644 --- a/packages/nocodb/src/lib/db/sql-client/lib/mssql/MssqlClient.ts +++ b/packages/nocodb/src/lib/db/sql-client/lib/mssql/MssqlClient.ts @@ -2629,43 +2629,14 @@ class MssqlClient extends KnexClient { ); } - if (n.dtxp !== o.dtxp && !['text'].includes(n.dt)) { + if (n.dtxp !== o.dtxp || n.dt !== o.dt || n.rqd !== o.rqd) { query += this.genQuery( - `\nALTER TABLE ?? ALTER COLUMN ?? ${n.dt}${!getDefaultLengthIsDisabled(n.dt) && n.dtxp ? `(${n.dtxp})` : ''};\n`, + `\nALTER TABLE ?? ALTER COLUMN ?? ${n.dt}${ + !getDefaultLengthIsDisabled(n.dt) && n.dtxp ? `(${n.dtxp})` : '' + }`, [this.getTnPath(t), n.cn], shouldSanitize ); - } else if (n.dt !== o.dt) { - query += this.genQuery( - `\nALTER TABLE ?? ALTER COLUMN ?? TYPE ${n.dt};\n`, - [this.getTnPath(t), n.cn], - shouldSanitize - ); - } - - if (n.rqd !== o.rqd) { - query += this.genQuery( - `\nALTER TABLE ?? ALTER COLUMN ?? ${n.dt}`, - [this.getTnPath(t), n.cn], - shouldSanitize - ); - if ( - ![ - 'int', - 'bigint', - 'bit', - 'real', - 'float', - 'decimal', - 'money', - 'smallint', - 'tinyint', - 'geometry', - 'datetime', - 'text', - ].includes(n.dt) - ) - query += n.dtxp && n.dtxp != -1 ? `(${n.dtxp})` : ''; query += n.rqd ? ` NOT NULL;\n` : ` NULL;\n`; } @@ -2787,14 +2758,6 @@ function getDefaultValue(n) { function getDefaultLengthIsDisabled(type) { switch (type) { - // case 'binary': - // case 'char': - // case 'sql_variant': - // case 'nvarchar': - // case 'nchar': - // case 'ntext': - // case 'varbinary': - // case 'sysname': case 'bigint': case 'bit': case 'datetimeoffset': From 9e968465bc7ba59a909b20353833015d3b0734ca Mon Sep 17 00:00:00 2001 From: Pranav C Date: Thu, 19 Jan 2023 16:37:34 +0530 Subject: [PATCH 04/27] fix(api): mssql - enable toggling scale and precision Signed-off-by: Pranav C --- packages/nocodb-sdk/src/lib/sqlUi/MssqlUi.ts | 28 +++++++++------- .../db/sql-client/lib/mssql/MssqlClient.ts | 33 +++++++++---------- 2 files changed, 32 insertions(+), 29 deletions(-) diff --git a/packages/nocodb-sdk/src/lib/sqlUi/MssqlUi.ts b/packages/nocodb-sdk/src/lib/sqlUi/MssqlUi.ts index 7762be3c4a..0e2b54a644 100644 --- a/packages/nocodb-sdk/src/lib/sqlUi/MssqlUi.ts +++ b/packages/nocodb-sdk/src/lib/sqlUi/MssqlUi.ts @@ -190,7 +190,7 @@ export class MssqlUi { return ''; case 'decimal': - return ''; + return '10'; case 'float': return ''; @@ -278,9 +278,14 @@ export class MssqlUi { static getDefaultLengthIsDisabled(type) { switch (type) { case 'nvarchar': + case 'numeric': + case 'decimal': + case 'float': + case 'bigint': + case 'int': + case 'tinyint': return false; - case 'bigint': case 'binary': case 'bit': case 'char': @@ -288,17 +293,13 @@ export class MssqlUi { case 'datetime': case 'datetime2': case 'datetimeoffset': - case 'decimal': - case 'float': case 'geography': case 'geometry': case 'heirarchyid': case 'image': - case 'int': case 'money': case 'nchar': case 'ntext': - case 'numeric': case 'real': case 'json': case 'smalldatetime': @@ -309,7 +310,6 @@ export class MssqlUi { case 'text': case 'time': case 'timestamp': - case 'tinyint': case 'uniqueidentifier': case 'varbinary': case 'xml': @@ -462,10 +462,10 @@ export class MssqlUi { return ''; case 'decimal': - return ''; + return '2'; case 'float': - return ''; + return '2'; case 'geography': return ''; @@ -492,7 +492,7 @@ export class MssqlUi { return ''; case 'numeric': - return ''; + return '2'; case 'nvarchar': return ''; @@ -598,8 +598,12 @@ export class MssqlUi { // } } - static showScale(_columnObj) { - return false; + static showScale(columnObj) { + return ( + columnObj.dt === 'float' || + columnObj.dt === 'decimal' || + columnObj.dt === 'numeric' + ); } static removeUnsigned(columns) { diff --git a/packages/nocodb/src/lib/db/sql-client/lib/mssql/MssqlClient.ts b/packages/nocodb/src/lib/db/sql-client/lib/mssql/MssqlClient.ts index 0f84e04461..294b902d0a 100644 --- a/packages/nocodb/src/lib/db/sql-client/lib/mssql/MssqlClient.ts +++ b/packages/nocodb/src/lib/db/sql-client/lib/mssql/MssqlClient.ts @@ -2580,11 +2580,15 @@ class MssqlClient extends KnexClient { const defaultValue = getDefaultValue(n); const shouldSanitize = true; + const scaleAndPrecision = + !getDefaultLengthIsDisabled(n.dt) && n.dtxp + ? `(${n.dtxp}${n.dtxs ? `,${n.dtxs}` : ''})` + : ''; if (change === 0) { query = existingQuery ? ',' : ''; query += this.genQuery(`?? ${n.dt}`, [n.cn], shouldSanitize); - query += !getDefaultLengthIsDisabled(n.dt) && n.dtxp ? `(${n.dtxp})` : ''; + query += scaleAndPrecision; query += n.rqd ? ' NOT NULL' : ' NULL'; query += n.ai ? ' IDENTITY(1,1)' : ' '; query += defaultValue @@ -2599,7 +2603,7 @@ class MssqlClient extends KnexClient { } } else if (change === 1) { query += this.genQuery(` ADD ?? ${n.dt}`, [n.cn], shouldSanitize); - query += !getDefaultLengthIsDisabled(n.dt) && n.dtxp ? `(${n.dtxp})` : ''; + query += scaleAndPrecision; query += n.rqd ? ' NOT NULL' : ' NULL'; query += n.ai ? ' IDENTITY(1,1)' : ' '; query += defaultValue @@ -2629,11 +2633,9 @@ class MssqlClient extends KnexClient { ); } - if (n.dtxp !== o.dtxp || n.dt !== o.dt || n.rqd !== o.rqd) { + if (n.dtxp !== o.dtxp ||n.dtxs !== o.dtxs || n.dt !== o.dt || n.rqd !== o.rqd) { query += this.genQuery( - `\nALTER TABLE ?? ALTER COLUMN ?? ${n.dt}${ - !getDefaultLengthIsDisabled(n.dt) && n.dtxp ? `(${n.dtxp})` : '' - }`, + `\nALTER TABLE ?? ALTER COLUMN ?? ${n.dt}${scaleAndPrecision}`, [this.getTnPath(t), n.cn], shouldSanitize ); @@ -2758,35 +2760,32 @@ function getDefaultValue(n) { function getDefaultLengthIsDisabled(type) { switch (type) { - case 'bigint': - case 'bit': case 'datetimeoffset': - case 'decimal': - case 'float': case 'geography': case 'geometry': case 'heirarchyid': case 'image': - case 'int': case 'money': - case 'numeric': case 'real': case 'json': case 'smalldatetime': - case 'smallint': case 'smallmoney': case 'text': case 'time': case 'timestamp': - case 'tinyint': case 'uniqueidentifier': case 'xml': return true; break; default: - case 'date': - case 'datetime': - case 'datetime2': + case 'int': + case 'tinyint': + case 'bigint': + case 'bit': + case 'decimal': + case 'float': + case 'numeric': + case 'smallint': case 'varchar': return false; break; From 918d0890615deb69033be1f4811d9252c27ef309 Mon Sep 17 00:00:00 2001 From: Pranav C Date: Thu, 19 Jan 2023 16:47:05 +0530 Subject: [PATCH 05/27] fix(api): hide length and scale for int and float types Signed-off-by: Pranav C --- packages/nocodb-sdk/src/lib/sqlUi/MssqlUi.ts | 15 +++++---------- .../db/sql-client/lib/mssql/MssqlClient.ts | 19 ++++++++++++------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/packages/nocodb-sdk/src/lib/sqlUi/MssqlUi.ts b/packages/nocodb-sdk/src/lib/sqlUi/MssqlUi.ts index 0e2b54a644..ba54975770 100644 --- a/packages/nocodb-sdk/src/lib/sqlUi/MssqlUi.ts +++ b/packages/nocodb-sdk/src/lib/sqlUi/MssqlUi.ts @@ -280,12 +280,11 @@ export class MssqlUi { case 'nvarchar': case 'numeric': case 'decimal': + return false; + case 'tinyint': case 'float': - case 'bigint': case 'int': - case 'tinyint': - return false; - + case 'bigint': case 'binary': case 'bit': case 'char': @@ -465,7 +464,7 @@ export class MssqlUi { return '2'; case 'float': - return '2'; + return ''; case 'geography': return ''; @@ -599,11 +598,7 @@ export class MssqlUi { } static showScale(columnObj) { - return ( - columnObj.dt === 'float' || - columnObj.dt === 'decimal' || - columnObj.dt === 'numeric' - ); + return columnObj.dt === 'decimal' || columnObj.dt === 'numeric'; } static removeUnsigned(columns) { diff --git a/packages/nocodb/src/lib/db/sql-client/lib/mssql/MssqlClient.ts b/packages/nocodb/src/lib/db/sql-client/lib/mssql/MssqlClient.ts index 294b902d0a..c7f59aafc1 100644 --- a/packages/nocodb/src/lib/db/sql-client/lib/mssql/MssqlClient.ts +++ b/packages/nocodb/src/lib/db/sql-client/lib/mssql/MssqlClient.ts @@ -2633,7 +2633,12 @@ class MssqlClient extends KnexClient { ); } - if (n.dtxp !== o.dtxp ||n.dtxs !== o.dtxs || n.dt !== o.dt || n.rqd !== o.rqd) { + if ( + n.dtxp !== o.dtxp || + n.dtxs !== o.dtxs || + n.dt !== o.dt || + n.rqd !== o.rqd + ) { query += this.genQuery( `\nALTER TABLE ?? ALTER COLUMN ?? ${n.dt}${scaleAndPrecision}`, [this.getTnPath(t), n.cn], @@ -2773,19 +2778,19 @@ function getDefaultLengthIsDisabled(type) { case 'text': case 'time': case 'timestamp': + case 'int': + case 'tinyint': + case 'bigint': + case 'bit': + case 'smallint': + case 'float': case 'uniqueidentifier': case 'xml': return true; break; default: - case 'int': - case 'tinyint': - case 'bigint': - case 'bit': case 'decimal': - case 'float': case 'numeric': - case 'smallint': case 'varchar': return false; break; From 7b08819fde09f1c6d9a26e440ba0fff2bfdca309 Mon Sep 17 00:00:00 2001 From: Pranav C Date: Thu, 19 Jan 2023 19:02:44 +0530 Subject: [PATCH 06/27] fix: convert input arg to string if a different type passed Signed-off-by: Pranav C --- packages/nc-gui/utils/urlUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/nc-gui/utils/urlUtils.ts b/packages/nc-gui/utils/urlUtils.ts index d9d807d446..2f0a071849 100644 --- a/packages/nc-gui/utils/urlUtils.ts +++ b/packages/nc-gui/utils/urlUtils.ts @@ -20,7 +20,7 @@ export const replaceUrlsWithLink = (text: string): boolean | string => { } export const isValidURL = (str: string) => { - return isURL(str) + return isURL(`${str}`) } export const openLink = (path: string, baseURL?: string, target = '_blank') => { From 5298c8e34039a10fe816588c422f769c9d2908b7 Mon Sep 17 00:00:00 2001 From: Pranav C Date: Fri, 20 Jan 2023 14:34:43 +0530 Subject: [PATCH 07/27] fix(gui): convert value to string to avoid database error Signed-off-by: Pranav C --- packages/nc-gui/utils/parsers/ExcelTemplateAdapter.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/nc-gui/utils/parsers/ExcelTemplateAdapter.ts b/packages/nc-gui/utils/parsers/ExcelTemplateAdapter.ts index d3d60b5359..f0628d7558 100644 --- a/packages/nc-gui/utils/parsers/ExcelTemplateAdapter.ts +++ b/packages/nc-gui/utils/parsers/ExcelTemplateAdapter.ts @@ -257,6 +257,8 @@ export default class ExcelTemplateAdapter extends TemplateGenerator { }) const cellObj = ws[cellId] rowData[table.columns[i].column_name] = (cellObj && cellObj.w) || row[i] + } else if (table.columns[i].uidt === UITypes.SingleLineText || table.columns[i].uidt === UITypes.LongText) { + rowData[table.columns[i].column_name] = `${row[i]}` } else { // TODO: do parsing if necessary based on type rowData[table.columns[i].column_name] = row[i] From f1be5c3ea624f7157e3d84f35ade2cb463f7be2f Mon Sep 17 00:00:00 2001 From: Pranav C Date: Sat, 21 Jan 2023 12:01:22 +0530 Subject: [PATCH 08/27] fix(gui): retain null/undefined as null while parsing for string type Signed-off-by: Pranav C --- packages/nc-gui/utils/parsers/ExcelTemplateAdapter.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/nc-gui/utils/parsers/ExcelTemplateAdapter.ts b/packages/nc-gui/utils/parsers/ExcelTemplateAdapter.ts index f0628d7558..9e2b087aa2 100644 --- a/packages/nc-gui/utils/parsers/ExcelTemplateAdapter.ts +++ b/packages/nc-gui/utils/parsers/ExcelTemplateAdapter.ts @@ -258,7 +258,7 @@ export default class ExcelTemplateAdapter extends TemplateGenerator { const cellObj = ws[cellId] rowData[table.columns[i].column_name] = (cellObj && cellObj.w) || row[i] } else if (table.columns[i].uidt === UITypes.SingleLineText || table.columns[i].uidt === UITypes.LongText) { - rowData[table.columns[i].column_name] = `${row[i]}` + rowData[table.columns[i].column_name] = row[i] === null || row[i] === undefined ? null : `${row[i]}` } else { // TODO: do parsing if necessary based on type rowData[table.columns[i].column_name] = row[i] From ade937a64b69bb590b417fed8c6cf5291d55647c Mon Sep 17 00:00:00 2001 From: mertmit Date: Sat, 21 Jan 2023 23:41:54 +0300 Subject: [PATCH 09/27] fix: filtering options for select columns Signed-off-by: mertmit --- packages/nc-gui/utils/filterUtils.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/nc-gui/utils/filterUtils.ts b/packages/nc-gui/utils/filterUtils.ts index 5f6ab8c414..f48c16d82e 100644 --- a/packages/nc-gui/utils/filterUtils.ts +++ b/packages/nc-gui/utils/filterUtils.ts @@ -41,13 +41,13 @@ export const comparisonOpList: { text: 'is empty', value: 'empty', ignoreVal: true, - excludedTypes: [UITypes.Checkbox, UITypes.Rating], + excludedTypes: [UITypes.Checkbox, UITypes.Rating, UITypes.MultiSelect, UITypes.SingleSelect], }, { text: 'is not empty', value: 'notempty', ignoreVal: true, - excludedTypes: [UITypes.Checkbox, UITypes.Rating], + excludedTypes: [UITypes.Checkbox, UITypes.Rating, UITypes.MultiSelect, UITypes.SingleSelect], }, { text: 'is null', @@ -67,7 +67,7 @@ export const comparisonOpList: { { text: 'contains any of', value: 'anyof', - includedTypes: [UITypes.MultiSelect], + includedTypes: [UITypes.MultiSelect, UITypes.SingleSelect], }, { text: 'does not contain all of', @@ -77,26 +77,26 @@ export const comparisonOpList: { { text: 'does not contain any of', value: 'nanyof', - includedTypes: [UITypes.MultiSelect], + includedTypes: [UITypes.MultiSelect, UITypes.SingleSelect], }, { text: '>', value: 'gt', - excludedTypes: [UITypes.Checkbox], + excludedTypes: [UITypes.Checkbox, UITypes.MultiSelect, UITypes.SingleSelect], }, { text: '<', value: 'lt', - excludedTypes: [UITypes.Checkbox], + excludedTypes: [UITypes.Checkbox, UITypes.MultiSelect, UITypes.SingleSelect], }, { text: '>=', value: 'gte', - excludedTypes: [UITypes.Checkbox], + excludedTypes: [UITypes.Checkbox, UITypes.MultiSelect, UITypes.SingleSelect], }, { text: '<=', value: 'lte', - excludedTypes: [UITypes.Checkbox], + excludedTypes: [UITypes.Checkbox, UITypes.MultiSelect, UITypes.SingleSelect], }, ] From ca85d2ab4190d690521636cea293b9088c1a7919 Mon Sep 17 00:00:00 2001 From: Raju Udava <86527202+dstala@users.noreply.github.com> Date: Mon, 23 Jan 2023 14:41:06 +0530 Subject: [PATCH 10/27] test: single select filter, sort Signed-off-by: Raju Udava <86527202+dstala@users.noreply.github.com> --- .../tests/columnSingleSelect.spec.ts | 93 +++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/tests/playwright/tests/columnSingleSelect.spec.ts b/tests/playwright/tests/columnSingleSelect.spec.ts index 03710b9075..59ff195c28 100644 --- a/tests/playwright/tests/columnSingleSelect.spec.ts +++ b/tests/playwright/tests/columnSingleSelect.spec.ts @@ -2,6 +2,7 @@ import { test } from '@playwright/test'; import { DashboardPage } from '../pages/Dashboard'; import { GridPage } from '../pages/Dashboard/Grid'; import setup from '../setup'; +import { ToolbarPage } from '../pages/Dashboard/common/Toolbar'; test.describe('Single select', () => { let dashboard: DashboardPage, grid: GridPage; @@ -93,3 +94,95 @@ test.describe('Single select', () => { await grid.column.delete({ title: 'SingleSelect' }); }); }); + +test.describe('Single select - filter & sort', () => { + // Row values + // no values (row ❶) + // only Foo (row ❷) + // only Bar (row ❸) + // only Baz (row ❹) + + // Example filters: + // + // where tags contains any of [Foo, Bar] + // result: rows 2,3 + // where tags does not contain any of [Foo, Bar] + // result: rows 1,4 + + let dashboard: DashboardPage, grid: GridPage, toolbar: ToolbarPage; + let context: any; + + test.beforeEach(async ({ page }) => { + context = await setup({ page }); + dashboard = new DashboardPage(page, context.project); + toolbar = dashboard.grid.toolbar; + grid = dashboard.grid; + + await dashboard.treeView.createTable({ title: 'sheet1' }); + + await grid.column.create({ title: 'SingleSelect', type: 'SingleSelect' }); + await grid.column.selectOption.addOptions({ + columnTitle: 'SingleSelect', + options: ['foo', 'bar', 'baz'], + }); + await grid.addNewRow({ index: 0, value: '1' }); + await grid.addNewRow({ index: 1, value: '2' }); + await grid.addNewRow({ index: 2, value: '3' }); + await grid.addNewRow({ index: 3, value: '4' }); + + await grid.cell.selectOption.select({ index: 1, columnHeader: 'SingleSelect', option: 'foo', multiSelect: false }); + await grid.cell.selectOption.select({ index: 2, columnHeader: 'SingleSelect', option: 'bar', multiSelect: false }); + await grid.cell.selectOption.select({ index: 3, columnHeader: 'SingleSelect', option: 'baz', multiSelect: false }); + }); + + // define validateRowArray function + async function validateRowArray(value: string[]) { + const length = value.length; + for (let i = 0; i < length; i++) { + await dashboard.grid.cell.verify({ + index: i, + columnHeader: 'Title', + value: value[i], + }); + } + } + + async function verifyFilter(param: { opType: string; value?: string; result: string[] }) { + await toolbar.clickFilter(); + await toolbar.filter.add({ + columnTitle: 'SingleSelect', + opType: param.opType, + value: param.value, + isLocallySaved: false, + }); + await toolbar.clickFilter(); + + // verify filtered rows + await validateRowArray(param.result); + // Reset filter + await toolbar.filter.reset(); + } + + test('Select and clear options and rename options', async () => { + await verifyFilter({ opType: 'contains any of', value: 'foo,bar', result: ['2', '3'] }); + await verifyFilter({ opType: 'does not contain any of', value: 'foo,bar', result: ['1', '4'] }); + + // Sort column + await toolbar.sort.add({ + columnTitle: 'SingleSelect', + isAscending: true, + isLocallySaved: false, + }); + await validateRowArray(['1', '3', '4', '2']); + await toolbar.sort.reset(); + + // sort descending & validate + await toolbar.sort.add({ + columnTitle: 'SingleSelect', + isAscending: false, + isLocallySaved: false, + }); + await validateRowArray(['2', '4', '3', '1']); + await toolbar.sort.reset(); + }); +}); From 88add83cf1ea4e979210e71c3aafd187700c7130 Mon Sep 17 00:00:00 2001 From: mertmit Date: Mon, 23 Jan 2023 17:26:41 +0300 Subject: [PATCH 11/27] fix: show empty filtering for select options Signed-off-by: mertmit --- packages/nc-gui/utils/filterUtils.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/nc-gui/utils/filterUtils.ts b/packages/nc-gui/utils/filterUtils.ts index f48c16d82e..f3454b0bc9 100644 --- a/packages/nc-gui/utils/filterUtils.ts +++ b/packages/nc-gui/utils/filterUtils.ts @@ -41,13 +41,13 @@ export const comparisonOpList: { text: 'is empty', value: 'empty', ignoreVal: true, - excludedTypes: [UITypes.Checkbox, UITypes.Rating, UITypes.MultiSelect, UITypes.SingleSelect], + excludedTypes: [UITypes.Checkbox, UITypes.Rating], }, { text: 'is not empty', value: 'notempty', ignoreVal: true, - excludedTypes: [UITypes.Checkbox, UITypes.Rating, UITypes.MultiSelect, UITypes.SingleSelect], + excludedTypes: [UITypes.Checkbox, UITypes.Rating], }, { text: 'is null', From 6f73dc2cd4cede7e86ce4d30ca533a8c8ee9aa21 Mon Sep 17 00:00:00 2001 From: Naveen MR Date: Mon, 23 Jan 2023 15:24:35 +0000 Subject: [PATCH 12/27] docs : mention where PR build can be found --- .../content/en/engineering/builds-and-releases.md | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/noco-docs/content/en/engineering/builds-and-releases.md b/packages/noco-docs/content/en/engineering/builds-and-releases.md index 9bce250f1c..4e24edba6e 100644 --- a/packages/noco-docs/content/en/engineering/builds-and-releases.md +++ b/packages/noco-docs/content/en/engineering/builds-and-releases.md @@ -11,7 +11,7 @@ There are 3 kinds of docker builds in NocoDB - Release builds [nocodb/nocodb](https://hub.docker.com/r/nocodb/nocodb) : built during NocoDB release. - Daily builds [nocodb/nocodb-daily](https://hub.docker.com/r/nocodb/nocodb-daily) : built every 6 hours from Develop branch. -- Daily builds [nocodb/nocodb-timely](https://hub.docker.com/r/nocodb/nocodb-timely): built for every PR. +- Timely builds [nocodb/nocodb-timely](https://hub.docker.com/r/nocodb/nocodb-timely): built for every PR and manually triggered PRs. Below is an overview of how to make these builds and what happens behind the scenes. @@ -118,7 +118,12 @@ Once the deployment is finished, there would be some new changes being pushed to ## Timely builds ### What are timely builds ? -NocoDB creates docker and binaries for each PR! +NocoDB has github actions which creates docker and binaries for each PR! And these can be found as a **comment on the last commit** of the PR. + +Example shown below +- Go to a PR and click on the comment. + +- Click on the link to copy the docker image and run it locally. This is to - reduce pull request cycle time @@ -135,7 +140,7 @@ The docker images will be built and pushed to Docker Hub (See [nocodb/nocodb-tim ![image](https://user-images.githubusercontent.com/35857179/175012097-240dab05-da93-4c4e-87c1-1c36fb1350bd.png) -## Executables or Binariess +## Executables or Binaries Similarly, we provide a timely build for executables for non-docker users. The source code will be built, packaged as binary files, and pushed to Github (See [nocodb/nocodb-timely](https://github.com/nocodb/nocodb-timely/releases) for the full list). @@ -157,4 +162,3 @@ NocoDB creates Docker and Binaries for each PR. This is to - reduce pull request cycle time - allow issue reporters / reviewers to verify the fix without setting up their local machines - From 90159005a6a04b188c31a4ae6ac612b74acc659f Mon Sep 17 00:00:00 2001 From: navi Date: Mon, 23 Jan 2023 15:47:42 +0000 Subject: [PATCH 13/27] Update builds-and-releases.md --- .../noco-docs/content/en/engineering/builds-and-releases.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/noco-docs/content/en/engineering/builds-and-releases.md b/packages/noco-docs/content/en/engineering/builds-and-releases.md index 4e24edba6e..b5da9ceac4 100644 --- a/packages/noco-docs/content/en/engineering/builds-and-releases.md +++ b/packages/noco-docs/content/en/engineering/builds-and-releases.md @@ -122,8 +122,11 @@ NocoDB has github actions which creates docker and binaries for each PR! And the Example shown below - Go to a PR and click on the comment. +Screenshot 2023-01-23 at 15 46 36 - Click on the link to copy the docker image and run it locally. +Screenshot 2023-01-23 at 15 46 55 + This is to - reduce pull request cycle time From 77b6d44bd24e8963e952a940227aa929bff3a1c4 Mon Sep 17 00:00:00 2001 From: Naveen MR Date: Mon, 23 Jan 2023 15:51:11 +0000 Subject: [PATCH 14/27] docs : CE vs EE --- packages/noco-docs/content/en/FAQs.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/noco-docs/content/en/FAQs.md b/packages/noco-docs/content/en/FAQs.md index 7b033ac23b..cce8e070fa 100644 --- a/packages/noco-docs/content/en/FAQs.md +++ b/packages/noco-docs/content/en/FAQs.md @@ -45,7 +45,7 @@ PackageVersion: **0.97.0** ``` ## What is available in free version ? - +- [Detailed comparison of NocoDB's generous CE compared to others is here](https://github.com/orgs/nocodb/projects/13). - NocoDB has just one version that is free & open source. - In it you will notice advanced features are all available for free. - ACL @@ -66,7 +66,6 @@ Auth Token is a JWT Token generated based on the logged-in user. By default, the API Token is a Nano ID with a length of 40. If you are passing API Token, make sure that the header is called `xc-token`. ## Do you plan to have Enterprise Edition ? - For features that make sense for enterprises like below - yes - SSO, SLA, Organisation wide reports and analytics, - Advanced Audit or ACL, From 48f58d730d5360e1eb1d8139794e09e6c6a95dfd Mon Sep 17 00:00:00 2001 From: Pranav C Date: Tue, 24 Jan 2023 11:58:49 +0530 Subject: [PATCH 15/27] fix(gui): skip keydown event handler if active cell value is `NaN` Signed-off-by: Pranav C --- packages/nc-gui/composables/useMultiSelect/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/nc-gui/composables/useMultiSelect/index.ts b/packages/nc-gui/composables/useMultiSelect/index.ts index 37a350379c..d596e82e84 100644 --- a/packages/nc-gui/composables/useMultiSelect/index.ts +++ b/packages/nc-gui/composables/useMultiSelect/index.ts @@ -171,7 +171,7 @@ export function useMultiSelect( return true } - if (activeCell.row === null || activeCell.col === null) { + if (activeCell.row === null || activeCell.col === null || isNaN(activeCell.row) || isNaN(activeCell.col)) { return } From a9fec148950eb65aa30917d2d5c57e527e3db110 Mon Sep 17 00:00:00 2001 From: Pranav C Date: Tue, 24 Jan 2023 12:17:42 +0530 Subject: [PATCH 16/27] fix(gui): skip expand row behaviour if active row value is NaN or null Signed-off-by: Pranav C --- packages/nc-gui/components/smartsheet/Grid.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/nc-gui/components/smartsheet/Grid.vue b/packages/nc-gui/components/smartsheet/Grid.vue index 09a9dd5b36..3a0992c513 100644 --- a/packages/nc-gui/components/smartsheet/Grid.vue +++ b/packages/nc-gui/components/smartsheet/Grid.vue @@ -202,7 +202,7 @@ const { isCellSelected, activeCell, handleMouseDown, handleMouseOver, handleCell const cmdOrCtrl = isMac() ? e.metaKey : e.ctrlKey const altOrOptionKey = e.altKey if (e.key === ' ') { - if (activeCell.row != null && !editEnabled && hasEditPermission) { + if (activeCell.row != null && !isNaN(activeCell.row) && !editEnabled && hasEditPermission) { e.preventDefault() clearSelectedRange() const row = data.value[activeCell.row] From 77ec4c17da1db29a90a47efd9f4daab7ea362010 Mon Sep 17 00:00:00 2001 From: Pranav C Date: Tue, 24 Jan 2023 12:41:14 +0530 Subject: [PATCH 17/27] fix(gui): skip ctrl+arrow navigation if active cell is null/NaN Signed-off-by: Pranav C --- .../nc-gui/components/smartsheet/Grid.vue | 338 +++++++++--------- 1 file changed, 169 insertions(+), 169 deletions(-) diff --git a/packages/nc-gui/components/smartsheet/Grid.vue b/packages/nc-gui/components/smartsheet/Grid.vue index 3a0992c513..000b41f034 100644 --- a/packages/nc-gui/components/smartsheet/Grid.vue +++ b/packages/nc-gui/components/smartsheet/Grid.vue @@ -156,8 +156,8 @@ const getContainerScrollForElement = ( relativePos.right + (offset?.right || 0) > 0 ? container.scrollLeft + relativePos.right + (offset?.right || 0) : relativePos.left - (offset?.left || 0) < 0 - ? container.scrollLeft + relativePos.left - (offset?.left || 0) - : container.scrollLeft + ? container.scrollLeft + relativePos.left - (offset?.left || 0) + : container.scrollLeft /* * If the element is below the container, scroll down (positive) @@ -167,8 +167,8 @@ const getContainerScrollForElement = ( relativePos.bottom + (offset?.bottom || 0) > 0 ? container.scrollTop + relativePos.bottom + (offset?.bottom || 0) : relativePos.top - (offset?.top || 0) < 0 - ? container.scrollTop + relativePos.top - (offset?.top || 0) - : container.scrollTop + ? container.scrollTop + relativePos.top - (offset?.top || 0) + : container.scrollTop return scroll } @@ -226,6 +226,8 @@ const { isCellSelected, activeCell, handleMouseDown, handleMouseOver, handleCell } if (cmdOrCtrl) { + if (activeCell.row === null || isNaN(activeCell.row) || activeCell.col === null || isNaN(activeCell.col)) return + switch (e.key) { case 'ArrowUp': e.preventDefault() @@ -672,105 +674,104 @@ const closeAddColumnDropdown = () => { @contextmenu="showContextMenu" > - - -
- - -
- - -
- + + +
+ + +
+ + -
- +
+ + +
+ + + +
+ +
- -
- - + + + + - - + + + + +
+ - + {{ $t('activity.addRow') }} -
- - +
+ + @@ -897,8 +898,7 @@ const closeAddColumnDropdown = () => {
- +
{{ $t('general.copy') }} From 196e4a5b61571b5a90357a680ba1e11843c2185d Mon Sep 17 00:00:00 2001 From: Pranav C Date: Tue, 24 Jan 2023 12:52:24 +0530 Subject: [PATCH 18/27] fix(gui): reload app info after setting license Signed-off-by: Pranav C --- packages/nc-gui/components/account/License.vue | 5 ++++- packages/nc-gui/composables/useGlobal/actions.ts | 11 ++++++++++- packages/nc-gui/composables/useGlobal/types.ts | 1 + 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/packages/nc-gui/components/account/License.vue b/packages/nc-gui/components/account/License.vue index a9160edf78..29cd19839b 100644 --- a/packages/nc-gui/components/account/License.vue +++ b/packages/nc-gui/components/account/License.vue @@ -1,12 +1,14 @@ - - - - diff --git a/packages/nc-gui/composables/useGlobal/state.ts b/packages/nc-gui/composables/useGlobal/state.ts index abd75a133f..c036002117 100644 --- a/packages/nc-gui/composables/useGlobal/state.ts +++ b/packages/nc-gui/composables/useGlobal/state.ts @@ -59,11 +59,6 @@ export function useGlobalState(storageKey = 'nocodb-gui-v2'): State { token: null, lang: preferredLanguage, darkMode: prefersDarkMode, - feedbackForm: { - url: 'https://docs.google.com/forms/d/e/1FAIpQLSeTlAfZjszgr53lArz3NvUEnJGOT9JtG9NAU5d0oQwunDS2Pw/viewform?embedded=true', - createdAt: new Date('2020-01-01T00:00:00.000Z').toISOString(), - isHidden: false, - }, filterAutoSave: true, previewAs: null, includeM2M: false, diff --git a/packages/nc-gui/composables/useGlobal/types.ts b/packages/nc-gui/composables/useGlobal/types.ts index c495dc34f8..ce9975e519 100644 --- a/packages/nc-gui/composables/useGlobal/types.ts +++ b/packages/nc-gui/composables/useGlobal/types.ts @@ -4,13 +4,6 @@ import type { JwtPayload } from 'jwt-decode' import type { Language, ProjectRole, User } from '~/lib' import type { useCounter } from '#imports' -export interface FeedbackForm { - url: string - createdAt: string - isHidden: boolean - lastFormPollDate?: string -} - export interface AppInfo { ncSiteUrl: string authType: 'jwt' | 'none' @@ -32,7 +25,6 @@ export interface StoredState { token: string | null lang: keyof typeof Language darkMode: boolean - feedbackForm: FeedbackForm filterAutoSave: boolean previewAs: ProjectRole | null includeM2M: boolean diff --git a/packages/nc-gui/plugins/feedbackForm.ts b/packages/nc-gui/plugins/feedbackForm.ts deleted file mode 100644 index 5c6e58955f..0000000000 --- a/packages/nc-gui/plugins/feedbackForm.ts +++ /dev/null @@ -1,41 +0,0 @@ -import dayjs from 'dayjs' -import { defineNuxtPlugin, useGlobal, useNuxtApp } from '#imports' - -const handleFeedbackForm = async () => { - let { feedbackForm: currentFeedbackForm } = $(useGlobal()) - - if (!currentFeedbackForm) return - - const { $api } = useNuxtApp() - - const isFirstTimePolling = !currentFeedbackForm.lastFormPollDate - - const now = dayjs() - - const lastFormPolledDate = dayjs(currentFeedbackForm.lastFormPollDate) - - if (isFirstTimePolling || dayjs.duration(now.diff(lastFormPolledDate)).days() > 0) { - $api.instance - .get('/api/v1/feedback_form') - .then((response) => { - try { - const { data: feedbackForm } = response - if (!feedbackForm.error) { - const isFetchedFormDuplicate = currentFeedbackForm.url === feedbackForm.url - - currentFeedbackForm = { - url: feedbackForm.url, - lastFormPollDate: now.toISOString(), - createdAt: feedbackForm.created_at, - isHidden: isFetchedFormDuplicate ? currentFeedbackForm.isHidden : false, - } - } - } catch (e) {} - }) - .catch(() => {}) - } -} - -export default defineNuxtPlugin(() => { - handleFeedbackForm() -}) diff --git a/packages/nocodb/src/lib/meta/api/utilApis.ts b/packages/nocodb/src/lib/meta/api/utilApis.ts index 6b7acef4eb..7db15d7243 100644 --- a/packages/nocodb/src/lib/meta/api/utilApis.ts +++ b/packages/nocodb/src/lib/meta/api/utilApis.ts @@ -16,7 +16,6 @@ import NcConfigFactory, { import User from '../../models/User'; import catchError from '../helpers/catchError'; import axios from 'axios'; -import { feedbackForm } from 'nc-help'; const versionCache = { releaseVersion: null, @@ -94,12 +93,6 @@ export async function versionInfo(_req: Request, res: Response) { res.json(response); } -export function feedbackFormGet(_req: Request, res: Response) { - feedbackForm() - .then((form) => res.json(form)) - .catch((e) => res.json({ error: e.message })); -} - export async function appHealth(_: Request, res: Response) { res.json({ message: 'OK', @@ -379,7 +372,6 @@ export default (router) => { router.post('/api/v1/db/meta/axiosRequestMake', catchError(axiosRequestMake)); router.get('/api/v1/version', catchError(versionInfo)); router.get('/api/v1/health', catchError(appHealth)); - router.get('/api/v1/feedback_form', catchError(feedbackFormGet)); router.post('/api/v1/url_to_config', catchError(urlToDbConfig)); router.get( '/api/v1/aggregated-meta-info',