Browse Source

Nc fix: rename id column if exist in import table (#8984)

* fix(nc-gui): rename id column if exist in import table

* fix(nc-gui): record already exist issue

* fix(nc-gui): import issue

* fix(nc-gui): duplicate table name issue

* Update QuickImport.vue

* fix(nc-gui): import data mapping issue

* fix(nc-gui): prevent user from using id as column name while importing csv

* fix(nc-gui): pr review changes

---------

Co-authored-by: Raju Udava <86527202+dstala@users.noreply.github.com>
pull/8991/head
Ramesh Mane 5 months ago committed by GitHub
parent
commit
2bd3b71648
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 2
      packages/nc-gui/components/dlg/QuickImport.vue
  2. 57
      packages/nc-gui/components/template/Editor.vue
  3. 4
      packages/nc-gui/helpers/parsers/CSVTemplateAdapter.ts
  4. 2
      packages/nc-gui/helpers/parsers/ExcelTemplateAdapter.ts
  5. 14
      packages/nc-gui/utils/validation.ts

2
packages/nc-gui/components/dlg/QuickImport.vue

@ -258,7 +258,7 @@ function populateUniqueTableName(tn: string, draftTn: string[] = []) {
const s = t.table_name.split('___')
let target = t.table_name
if (s.length > 1) target = s[1]
return target === `${tn}`
return target === `${tn}` || t.table_name === `${tn}`
})
) {
tn = `${tn}_${c++}`

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

@ -145,7 +145,11 @@ const validators = computed(() =>
hasSelectColumn.value[tableIdx] = false
table.columns?.forEach((column, columnIdx) => {
acc[`tables.${tableIdx}.columns.${columnIdx}.title`] = [fieldRequiredValidator(), fieldLengthValidator()]
acc[`tables.${tableIdx}.columns.${columnIdx}.title`] = [
fieldRequiredValidator(),
fieldLengthValidator(),
reservedFieldNameValidator(),
]
acc[`tables.${tableIdx}.columns.${columnIdx}.uidt`] = [fieldRequiredValidator()]
if (isSelect(column)) {
hasSelectColumn.value[tableIdx] = true
@ -237,6 +241,10 @@ function parseTemplate({ tables = [], ...rest }: Props['baseTemplate']) {
...rest,
columns: [
...columns.map((c: any, idx: number) => {
if (!importDataOnly && c.column_name?.toLowerCase() === 'id') {
const cn = populateUniqueColumnName('id', [], columns)
c.column_name = cn
}
c.key = idx
return c
}),
@ -282,6 +290,9 @@ function remapColNames(batchData: any[], columns: ColumnType[]) {
const dateFormatMap: Record<number, string> = {}
return batchData.map((data) =>
(columns || []).reduce((aggObj, col: Record<string, any>) => {
// we renaming existing id column and using our own auto increment id
if (col.uidt === UITypes.ID) return aggObj
// for excel & json, if the column name is changed in TemplateEditor,
// then only col.column_name exists in data, else col.ref_column_name
// for csv, col.column_name always exists in data
@ -570,6 +581,7 @@ async function importTemplate() {
await $api.dbTableColumn.primaryColumnSet(createdTable.columns[0].id as string)
}
}
// bulk insert data
if (importData) {
const offset = maxRowsToParse
@ -623,7 +635,7 @@ function mapDefaultColumns() {
srcDestMapping.value = {}
for (let i = 0; i < data.tables.length; i++) {
for (const col of importColumns[i]) {
const o = { srcCn: col.column_name, destCn: '', enabled: true }
const o = { srcCn: col.column_name, srcTitle: col.title, destCn: '', enabled: true }
if (columns.value) {
const tableColumn = columns.value.find((c) => c.column_name === col.column_name)
if (tableColumn) {
@ -712,6 +724,20 @@ const setErrorState = (errorsFields: any[]) => {
formError.value = errorMap
}
function populateUniqueColumnName(cn: string, draftCn: string[] = [], columns: ColumnType[]) {
let c = 2
let columnName = `${cn}${1}`
while (
draftCn.includes(columnName) ||
columns?.some((c) => {
return c.column_name === columnName || c.title === columnName
})
) {
columnName = `${cn}${c++}`
}
return columnName
}
watch(formRef, () => {
setTimeout(async () => {
try {
@ -801,8 +827,8 @@ watch(modelRef, async () => {
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'source_column'">
<NcTooltip class="truncate inline-block">
<template #title>{{ record.srcCn }}</template>
{{ record.srcCn }}
<template #title>{{ record.srcTitle }}</template>
{{ record.srcTitle }}
</NcTooltip>
</template>
@ -917,17 +943,29 @@ watch(modelRef, async () => {
<template #bodyCell="{ column, record }">
<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}.title`]"
class="nc-table-field-name"
>
<a-input
:ref="(el: HTMLInputElement) => (inputRefs[record.key] = el)"
v-model:value="record.title"
class="!rounded-md"
/>
>
<template #suffix>
<NcTooltip v-if="formError?.[`tables.${tableIdx}.columns.${record.key}.title`]" class="flex">
<template #title
>{{ formError?.[`tables.${tableIdx}.columns.${record.key}.title`].join('\n') }}
</template>
<GeneralIcon icon="info" class="h-4 w-4 text-red-500 flex-none" />
</NcTooltip>
</template>
</a-input>
</a-form-item>
</template>
<template v-else-if="column.key === 'uidt'">
<a-form-item v-bind="validateInfos[`tables.${tableIdx}.columns.${record.key}.${column.key}`]">
<a-form-item v-bind="validateInfos[`tables.${tableIdx}.columns.${record.key}.uidt`]">
<NcTooltip :disabled="importDataOnly">
<template #title>
{{ $t('tooltip.useFieldEditMenuToConfigFieldType') }}
@ -1014,4 +1052,9 @@ watch(modelRef, async () => {
@apply flex;
}
}
.nc-table-field-name {
:deep(.ant-form-item-explain) {
@apply hidden;
}
}
</style>

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

@ -45,7 +45,7 @@ export default class CSVTemplateAdapter {
initTemplate(tableIdx: number, tn: string, columnNames: string[]) {
const columnNameRowExist = +columnNames.every((v: any) => v === null || typeof v === 'string')
const columnNamePrefixRef: Record<string, any> = { id: 0 }
const columnNamePrefixRef: Record<string, any> = { id: 0, Id: 0 }
const tableObj: Record<string, any> = {
table_name: tn,
@ -61,9 +61,11 @@ export default class CSVTemplateAdapter {
let cn: string = ((columnNameRowExist && columnName.toString().trim()) || `field_${columnIdx + 1}`)
.replace(/[` ~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/g, '_')
.trim()
while (cn in columnNamePrefixRef) {
cn = `${cn}${++columnNamePrefixRef[cn]}`
}
columnNamePrefixRef[cn] = 0
this.detectedColumnTypes[columnIdx] = {}

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

@ -65,7 +65,7 @@ export default class ExcelTemplateAdapter extends TemplateGenerator {
this.progress(`Parsing sheet ${sheetName}`)
await new Promise((resolve) => {
const columnNamePrefixRef: Record<string, any> = { id: 0 }
const columnNamePrefixRef: Record<string, any> = { id: 0, Id: 0 }
let tn: string = (sheet || 'table').replace(/[` ~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/g, '_').trim()
while (tn in tableNamePrefixRef) {

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

@ -123,6 +123,20 @@ export const fieldLengthValidator = () => {
},
}
}
export const reservedFieldNameValidator = () => {
return {
validator: (rule: any, value: any) => {
const { t } = getI18n().global
return new Promise((resolve, reject) => {
if (value?.toLowerCase() === 'id') {
reject(new Error(t('msg.error.duplicateSystemColumnName')))
}
resolve(true)
})
},
}
}
export const importUrlValidator = {
validator: (rule: any, value: any) => {

Loading…
Cancel
Save