Browse Source

Merge pull request #7092 from nocodb/nc-fix/title-len

fix: deprecate title length validator and use title on import editor
pull/6066/merge
mertmit 12 months ago committed by GitHub
parent
commit
eb561d522d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 11
      packages/nc-gui/components/template/Editor.vue
  2. 2
      packages/nc-gui/composables/useColumnCreateStore.ts
  3. 2
      packages/nc-gui/helpers/parsers/CSVTemplateAdapter.ts
  4. 5
      packages/nc-gui/helpers/parsers/ExcelTemplateAdapter.ts
  5. 2
      packages/nc-gui/helpers/parsers/JSONTemplateAdapter.ts
  6. 18
      packages/nc-gui/utils/validation.ts
  7. 7
      packages/nocodb/src/services/tables.service.ts
  8. 2
      tests/playwright/tests/db/features/import.spec.ts

11
packages/nc-gui/components/template/Editor.vue

@ -131,9 +131,9 @@ const validators = computed(() =>
hasSelectColumn.value[tableIdx] = false hasSelectColumn.value[tableIdx] = false
table.columns?.forEach((column, columnIdx) => { table.columns?.forEach((column, columnIdx) => {
acc[`tables.${tableIdx}.columns.${columnIdx}.column_name`] = [ acc[`tables.${tableIdx}.columns.${columnIdx}.title`] = [
fieldRequiredValidator(), fieldRequiredValidator(),
fieldLengthValidator(base.value?.sources?.[0].type || ClientType.MYSQL), fieldLengthValidator(),
] ]
acc[`tables.${tableIdx}.columns.${columnIdx}.uidt`] = [fieldRequiredValidator()] acc[`tables.${tableIdx}.columns.${columnIdx}.uidt`] = [fieldRequiredValidator()]
if (isSelect(column)) { if (isSelect(column)) {
@ -252,6 +252,7 @@ function deleteTableColumn(tableIdx: number, columnKey: number) {
function addNewColumnRow(tableIdx: number, uidt: string) { function addNewColumnRow(tableIdx: number, uidt: string) {
data.tables[tableIdx].columns.push({ data.tables[tableIdx].columns.push({
key: data.tables[tableIdx].columns.length, key: data.tables[tableIdx].columns.length,
title: `title${data.tables[tableIdx].columns.length + 1}`,
column_name: `title${data.tables[tableIdx].columns.length + 1}`, column_name: `title${data.tables[tableIdx].columns.length + 1}`,
uidt, uidt,
}) })
@ -275,7 +276,7 @@ function remapColNames(batchData: any[], columns: ColumnType[]) {
// then only col.column_name exists in data, else col.ref_column_name // then only col.column_name exists in data, else col.ref_column_name
// for csv, col.column_name always exists in data // for csv, col.column_name always exists in data
// since it streams the data in getData() with the updated col.column_name // since it streams the data in getData() with the updated col.column_name
const key = col.column_name in data ? col.column_name : col.ref_column_name const key = col.title in data ? col.title : col.ref_column_name
let d = data[key] let d = data[key]
if (col.uidt === UITypes.Date && d) { if (col.uidt === UITypes.Date && d) {
let dateFormat let dateFormat
@ -295,7 +296,7 @@ function remapColNames(batchData: any[], columns: ColumnType[]) {
} }
return { return {
...aggObj, ...aggObj,
[col.column_name]: d, [col.title]: d,
} }
}, {}), }, {}),
) )
@ -901,7 +902,7 @@ watch(modelRef, async () => {
<template #bodyCell="{ column, record }"> <template #bodyCell="{ column, record }">
<template v-if="column.key === 'column_name'"> <template v-if="column.key === 'column_name'">
<a-form-item v-bind="validateInfos[`tables.${tableIdx}.columns.${record.key}.${column.key}`]"> <a-form-item v-bind="validateInfos[`tables.${tableIdx}.columns.${record.key}.${column.key}`]">
<a-input :ref="(el: HTMLInputElement) => (inputRefs[record.key] = el)" v-model:value="record.column_name" /> <a-input :ref="(el: HTMLInputElement) => (inputRefs[record.key] = el)" v-model:value="record.title" />
</a-form-item> </a-form-item>
</template> </template>

2
packages/nc-gui/composables/useColumnCreateStore.ts

@ -136,7 +136,7 @@ const [useProvideColumnCreateStore, useColumnCreateStore] = createInjectionState
}) })
}, },
}, },
fieldLengthValidator(source.value?.type || ClientType.MYSQL), fieldLengthValidator(),
], ],
uidt: [ uidt: [
{ {

2
packages/nc-gui/helpers/parsers/CSVTemplateAdapter.ts

@ -58,6 +58,7 @@ export default class CSVTemplateAdapter {
this.tables[tableIdx] = [] this.tables[tableIdx] = []
for (const [columnIdx, columnName] of columnNames.entries()) { for (const [columnIdx, columnName] of columnNames.entries()) {
let title = ((columnNameRowExist && columnName.toString().trim()) || `Field ${columnIdx + 1}`).trim()
let cn: string = ((columnNameRowExist && columnName.toString().trim()) || `field_${columnIdx + 1}`) let cn: string = ((columnNameRowExist && columnName.toString().trim()) || `field_${columnIdx + 1}`)
.replace(/[` ~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/g, '_') .replace(/[` ~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/g, '_')
.trim() .trim()
@ -70,6 +71,7 @@ export default class CSVTemplateAdapter {
this.distinctValues[columnIdx] = new Set<string>() this.distinctValues[columnIdx] = new Set<string>()
this.columnValues[columnIdx] = [] this.columnValues[columnIdx] = []
tableObj.columns.push({ tableObj.columns.push({
title,
column_name: cn, column_name: cn,
ref_column_name: cn, ref_column_name: cn,
meta: {}, meta: {},

5
packages/nc-gui/helpers/parsers/ExcelTemplateAdapter.ts

@ -113,6 +113,10 @@ export default class ExcelTemplateAdapter extends TemplateGenerator {
) )
for (let col = 0; col < rows[0].length; col++) { for (let col = 0; col < rows[0].length; col++) {
const title = (
(this.config.firstRowAsHeaders && rows[0] && rows[0][col] && rows[0][col].toString().trim()) ||
`Field ${col + 1}`
).trim()
let cn: string = ( let cn: string = (
(this.config.firstRowAsHeaders && rows[0] && rows[0][col] && rows[0][col].toString().trim()) || (this.config.firstRowAsHeaders && rows[0] && rows[0][col] && rows[0][col].toString().trim()) ||
`field_${col + 1}` `field_${col + 1}`
@ -126,6 +130,7 @@ export default class ExcelTemplateAdapter extends TemplateGenerator {
columnNamePrefixRef[cn] = 0 columnNamePrefixRef[cn] = 0
const column: Record<string, any> = { const column: Record<string, any> = {
title,
column_name: cn, column_name: cn,
ref_column_name: cn, ref_column_name: cn,
meta: {}, meta: {},

2
packages/nc-gui/helpers/parsers/JSONTemplateAdapter.ts

@ -90,8 +90,10 @@ export default class JSONTemplateAdapter extends TemplateGenerator {
columns.push(...normalizedNestedColumns) columns.push(...normalizedNestedColumns)
} }
} else { } else {
const title = path.join(' ').trim()
const cn = path.join('_').replace(/\W/g, '_').trim() const cn = path.join('_').replace(/\W/g, '_').trim()
const column: Record<string, any> = { const column: Record<string, any> = {
title,
column_name: cn, column_name: cn,
ref_column_name: cn, ref_column_name: cn,
uidt: UITypes.SingleLineText, uidt: UITypes.SingleLineText,

18
packages/nc-gui/utils/validation.ts

@ -102,21 +102,17 @@ export const fieldRequiredValidator = () => {
} }
} }
export const fieldLengthValidator = (sqlClientType: string) => { export const fieldLengthValidator = () => {
return { return {
validator: (rule: any, value: any) => { validator: (rule: any, value: any) => {
const { t } = getI18n().global const { t } = getI18n().global
// no limit for sqlite but set as 255 /// mysql allows 64 characters for column_name
let fieldLengthLimit = 255 // postgres allows 59 characters for column_name
// mssql allows 128 characters for column_name
if (sqlClientType === 'mysql2' || sqlClientType === 'mysql') { // sqlite allows any number of characters for column_name
fieldLengthLimit = 64 // We allow 255 for all databases, truncate will be handled by backend for column_name
} else if (sqlClientType === 'pg') { const fieldLengthLimit = 255
fieldLengthLimit = 59
} else if (sqlClientType === 'mssql') {
fieldLengthLimit = 128
}
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (value?.length > fieldLengthLimit) { if (value?.length > fieldLengthLimit) {

7
packages/nocodb/src/services/tables.service.ts

@ -459,7 +459,12 @@ export class TablesService {
for (const column of param.table.columns) { for (const column of param.table.columns) {
if (!isVirtualCol(column)) { if (!isVirtualCol(column)) {
column.column_name = sanitizeColumnName(column.column_name); const mxColumnLength = Column.getMaxColumnNameLength(sqlClientType);
// - 5 is a buffer for suffix
column.column_name = sanitizeColumnName(
column.column_name.slice(0, mxColumnLength - 5),
);
if (uniqueColumnNameCount[column.column_name]) { if (uniqueColumnNameCount[column.column_name]) {
let suffix = 1; let suffix = 1;

2
tests/playwright/tests/db/features/import.spec.ts

@ -56,7 +56,7 @@ test.describe('Import', () => {
await dashboard.treeView.openTable({ title: 'Sheet2' }); await dashboard.treeView.openTable({ title: 'Sheet2' });
const recordCells = { Number: '1', Float: '1.1', Text: 'abc' }; const recordCells = { number: '1', float: '1.1', text: 'abc' };
for (const [key, value] of Object.entries(recordCells)) { for (const [key, value] of Object.entries(recordCells)) {
await dashboard.grid.cell.verify({ await dashboard.grid.cell.verify({

Loading…
Cancel
Save