diff --git a/packages/nc-gui/components/template/Editor.vue b/packages/nc-gui/components/template/Editor.vue index c984474c2b..915ecccb2f 100644 --- a/packages/nc-gui/components/template/Editor.vue +++ b/packages/nc-gui/components/template/Editor.vue @@ -1,6 +1,8 @@ - + > + + + + {{ option.label }} + + + diff --git a/packages/nc-gui/package-lock.json b/packages/nc-gui/package-lock.json index 860fb59dd2..81a45e80bb 100644 --- a/packages/nc-gui/package-lock.json +++ b/packages/nc-gui/package-lock.json @@ -33,7 +33,7 @@ "vue-github-button": "^3.0.3", "vue-i18n": "^9.2.2", "vuedraggable": "^4.1.0", - "xlsx": "^0.17.3" + "xlsx": "^0.18.5" }, "devDependencies": { "@antfu/eslint-config": "^0.26.0", @@ -4220,16 +4220,9 @@ } }, "node_modules/adler-32": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/adler-32/-/adler-32-1.2.0.tgz", - "integrity": "sha512-/vUqU/UY4MVeFsg+SsK6c+/05RZXIHZMGJA+PX5JyWI0ZRcBpupnRuPLU/NXXoFwMYCPCoxIfElM2eS+DUXCqQ==", - "dependencies": { - "exit-on-epipe": "~1.0.1", - "printj": "~1.1.0" - }, - "bin": { - "adler32": "bin/adler32.njs" - }, + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/adler-32/-/adler-32-1.3.1.tgz", + "integrity": "sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==", "engines": { "node": ">=0.8" } @@ -4882,14 +4875,6 @@ "node": ">=0.8" } }, - "node_modules/cfb/node_modules/adler-32": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/adler-32/-/adler-32-1.3.1.tgz", - "integrity": "sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==", - "engines": { - "node": ">=0.8" - } - }, "node_modules/chai": { "version": "4.3.6", "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.6.tgz", @@ -7964,14 +7949,6 @@ "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, - "node_modules/exit-on-epipe": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/exit-on-epipe/-/exit-on-epipe-1.0.1.tgz", - "integrity": "sha512-h2z5mrROTxce56S+pnvAV890uu7ls7f1kEvVGJbw1OlFH3/mlJ5bkXu0KRyW94v37zzHPiUd55iLn3DA7TjWpw==", - "engines": { - "node": ">=0.8" - } - }, "node_modules/expand-template": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", @@ -13103,17 +13080,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/printj": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/printj/-/printj-1.1.2.tgz", - "integrity": "sha512-zA2SmoLaxZyArQTOPj5LXecR+RagfPSU5Kw1qP+jkWeNlrq+eJZyY2oS68SU1Z/7/myXM4lo9716laOFAVStCQ==", - "bin": { - "printj": "bin/printj.njs" - }, - "engines": { - "node": ">=0.8" - } - }, "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -16433,14 +16399,14 @@ } }, "node_modules/xlsx": { - "version": "0.17.5", - "resolved": "https://registry.npmjs.org/xlsx/-/xlsx-0.17.5.tgz", - "integrity": "sha512-lXNU0TuYsvElzvtI6O7WIVb9Zar1XYw7Xb3VAx2wn8N/n0whBYrCnHMxtFyIiUU1Wjf09WzmLALDfBO5PqTb1g==", + "version": "0.18.5", + "resolved": "https://registry.npmjs.org/xlsx/-/xlsx-0.18.5.tgz", + "integrity": "sha512-dmg3LCjBPHZnQp5/F/+nnTa+miPJxUXB6vtk42YjBBKayDNagxGEeIdWApkYPOf3Z3pm3k62Knjzp7lMeTEtFQ==", "dependencies": { - "adler-32": "~1.2.0", - "cfb": "^1.1.4", + "adler-32": "~1.3.0", + "cfb": "~1.2.1", "codepage": "~1.15.0", - "crc-32": "~1.2.0", + "crc-32": "~1.2.1", "ssf": "~0.11.2", "wmf": "~1.0.1", "word": "~0.3.0" @@ -19663,13 +19629,9 @@ "peer": true }, "adler-32": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/adler-32/-/adler-32-1.2.0.tgz", - "integrity": "sha512-/vUqU/UY4MVeFsg+SsK6c+/05RZXIHZMGJA+PX5JyWI0ZRcBpupnRuPLU/NXXoFwMYCPCoxIfElM2eS+DUXCqQ==", - "requires": { - "exit-on-epipe": "~1.0.1", - "printj": "~1.1.0" - } + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/adler-32/-/adler-32-1.3.1.tgz", + "integrity": "sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==" }, "agent-base": { "version": "6.0.2", @@ -20132,13 +20094,6 @@ "requires": { "adler-32": "~1.3.0", "crc-32": "~1.2.0" - }, - "dependencies": { - "adler-32": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/adler-32/-/adler-32-1.3.1.tgz", - "integrity": "sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==" - } } }, "chai": { @@ -22346,11 +22301,6 @@ "strip-final-newline": "^2.0.0" } }, - "exit-on-epipe": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/exit-on-epipe/-/exit-on-epipe-1.0.1.tgz", - "integrity": "sha512-h2z5mrROTxce56S+pnvAV890uu7ls7f1kEvVGJbw1OlFH3/mlJ5bkXu0KRyW94v37zzHPiUd55iLn3DA7TjWpw==" - }, "expand-template": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", @@ -26135,11 +26085,6 @@ "integrity": "sha512-6UqkYefdogmzqAZWzJ7laYeJnaXDy2/J+ZqiiMtS7t7OfpXWTlaeGMwX8U6EFvPV/YWWEKRkS8hKS4k60WHTOg==", "dev": true }, - "printj": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/printj/-/printj-1.1.2.tgz", - "integrity": "sha512-zA2SmoLaxZyArQTOPj5LXecR+RagfPSU5Kw1qP+jkWeNlrq+eJZyY2oS68SU1Z/7/myXM4lo9716laOFAVStCQ==" - }, "process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -28599,14 +28544,14 @@ "requires": {} }, "xlsx": { - "version": "0.17.5", - "resolved": "https://registry.npmjs.org/xlsx/-/xlsx-0.17.5.tgz", - "integrity": "sha512-lXNU0TuYsvElzvtI6O7WIVb9Zar1XYw7Xb3VAx2wn8N/n0whBYrCnHMxtFyIiUU1Wjf09WzmLALDfBO5PqTb1g==", + "version": "0.18.5", + "resolved": "https://registry.npmjs.org/xlsx/-/xlsx-0.18.5.tgz", + "integrity": "sha512-dmg3LCjBPHZnQp5/F/+nnTa+miPJxUXB6vtk42YjBBKayDNagxGEeIdWApkYPOf3Z3pm3k62Knjzp7lMeTEtFQ==", "requires": { - "adler-32": "~1.2.0", - "cfb": "^1.1.4", + "adler-32": "~1.3.0", + "cfb": "~1.2.1", "codepage": "~1.15.0", - "crc-32": "~1.2.0", + "crc-32": "~1.2.1", "ssf": "~0.11.2", "wmf": "~1.0.1", "word": "~0.3.0" diff --git a/packages/nc-gui/package.json b/packages/nc-gui/package.json index 2d4df35bce..17202ef833 100644 --- a/packages/nc-gui/package.json +++ b/packages/nc-gui/package.json @@ -42,7 +42,7 @@ "vue-github-button": "^3.0.3", "vue-i18n": "^9.2.2", "vuedraggable": "^4.1.0", - "xlsx": "^0.17.3" + "xlsx": "^0.18.5" }, "devDependencies": { "@antfu/eslint-config": "^0.26.0", diff --git a/packages/nc-gui/utils/dateTimeUtils.ts b/packages/nc-gui/utils/dateTimeUtils.ts index 5272df19de..a1f55a62ca 100644 --- a/packages/nc-gui/utils/dateTimeUtils.ts +++ b/packages/nc-gui/utils/dateTimeUtils.ts @@ -42,3 +42,12 @@ export function validateDateWithUnknownFormat(v: string) { } return res } + +export function getDateFormat(v: string) { + for (const format of dateFormats) { + if (dayjs(v, format, true).isValid()) { + return format + } + } + return 'YYYY/MM/DD' +} diff --git a/packages/nc-gui/utils/parsers/ExcelTemplateAdapter.ts b/packages/nc-gui/utils/parsers/ExcelTemplateAdapter.ts index 6e1b9ea4c9..8bfe2323b4 100644 --- a/packages/nc-gui/utils/parsers/ExcelTemplateAdapter.ts +++ b/packages/nc-gui/utils/parsers/ExcelTemplateAdapter.ts @@ -72,6 +72,9 @@ export default class ExcelTemplateAdapter extends TemplateGenerator { parse() { const tableNamePrefixRef: Record = {} + // TODO: find the upper bound / make it configurable + const maxSelectOptionsAllowed = 64 + for (let i = 0; i < this.wb.SheetNames.length; i++) { const columnNamePrefixRef: Record = { id: 0 } const sheet: any = this.wb.SheetNames[i] @@ -128,8 +131,6 @@ export default class ExcelTemplateAdapter extends TemplateGenerator { ref_column_name: cn, } - table.columns.push(column) - // const cellId = `${col.toString(26).split('').map(s => (parseInt(s, 26) + 10).toString(36).toUpperCase())}2`; const cellId = this.xlsx.utils.encode_cell({ c: range.s.c + col, @@ -153,11 +154,8 @@ export default class ExcelTemplateAdapter extends TemplateGenerator { if (checkboxType.length === 1) { column.uidt = UITypes.Checkbox } else { - // todo: optimize - // check column is multi or single select by comparing unique values - // todo: if (vals.some((v: any) => v && v.toString().includes(','))) { - let flattenedVals = vals.flatMap((v: any) => + const flattenedVals = vals.flatMap((v: any) => v ? v .toString() @@ -165,19 +163,41 @@ export default class ExcelTemplateAdapter extends TemplateGenerator { .split(/\s*,\s*/) : [], ) - const uniqueVals = (flattenedVals = flattenedVals.filter( - (v: any, i: any, arr: any) => i === arr.findIndex((v1: any) => v.toLowerCase() === v1.toLowerCase()), - )) - if (flattenedVals.length > uniqueVals.length && uniqueVals.length <= Math.ceil(flattenedVals.length / 2)) { - column.uidt = UITypes.MultiSelect + + // TODO: handle case sensitive case + const uniqueVals = [...new Set(flattenedVals.map((v: any) => v.toString().trim().toLowerCase()))] + + if (uniqueVals.length > maxSelectOptionsAllowed) { + // too many options are detected, convert the column to SingleLineText instead + column.uidt = UITypes.SingleLineText + // _disableSelect is used to disable the in TemplateEditor + column._disableSelect = true + } else { + // assume the column type is multiple select if there are repeated values + if (flattenedVals.length > uniqueVals.length && uniqueVals.length <= Math.ceil(flattenedVals.length / 2)) { + column.uidt = UITypes.MultiSelect + } + // set dtxp here so that users can have the options even they switch the type from other types to MultiSelect + // once it's set, dtxp needs to be reset if the final column type is not MultiSelect column.dtxp = `'${uniqueVals.join("','")}'` } } else { - const uniqueVals = vals - .map((v: any) => v.toString().trim()) - .filter((v: any, i: any, arr: any) => i === arr.findIndex((v1: any) => v.toLowerCase() === v1.toLowerCase())) - if (vals.length > uniqueVals.length && uniqueVals.length <= Math.ceil(vals.length / 2)) { - column.uidt = UITypes.SingleSelect + // TODO: handle case sensitive case + const uniqueVals = [...new Set(vals.map((v: any) => v.toString().trim().toLowerCase()))] + + if (uniqueVals.length > maxSelectOptionsAllowed) { + // too many options are detected, convert the column to SingleLineText instead + column.uidt = UITypes.SingleLineText + // _disableSelect is used to disable the in TemplateEditor + column._disableSelect = true + } else { + // assume the column type is single select if there are repeated values + // once it's set, dtxp needs to be reset if the final column type is not Single Select + if (vals.length > uniqueVals.length && uniqueVals.length <= Math.ceil(vals.length / 2)) { + column.uidt = UITypes.SingleSelect + } + // set dtxp here so that users can have the options even they switch the type from other types to SingleSelect + // once it's set, dtxp needs to be reset if the final column type is not SingleSelect column.dtxp = `'${uniqueVals.join("','")}'` } } @@ -220,6 +240,7 @@ export default class ExcelTemplateAdapter extends TemplateGenerator { column.uidt = UITypes.Date } } + table.columns.push(column) } let rowIndex = 0