Browse Source

refactor(nc-gui): use parserhelpers functions for import

pull/4135/head
Wing-Kam Wong 2 years ago
parent
commit
15024005d0
  1. 73
      packages/nc-gui/utils/parsers/ExcelTemplateAdapter.ts
  2. 41
      packages/nc-gui/utils/parsers/JSONTemplateAdapter.ts
  3. 70
      packages/nc-gui/utils/parsers/parserHelpers.ts

73
packages/nc-gui/utils/parsers/ExcelTemplateAdapter.ts

@ -1,6 +1,13 @@
import { UITypes } from 'nocodb-sdk' import { UITypes } from 'nocodb-sdk'
import TemplateGenerator from './TemplateGenerator' import TemplateGenerator from './TemplateGenerator'
import { getCheckboxValue, isCheckboxType } from './parserHelpers' import {
extractMultiOrSingleSelectProps,
getCheckboxValue,
isCheckboxType,
isEmailType,
isMultiLineTextType,
isUrlType,
} from './parserHelpers'
import { getDateFormat } from '~/utils' import { getDateFormat } from '~/utils'
const excelTypeToUidt: Record<string, UITypes> = { const excelTypeToUidt: Record<string, UITypes> = {
@ -73,9 +80,6 @@ export default class ExcelTemplateAdapter extends TemplateGenerator {
parse() { parse() {
const tableNamePrefixRef: Record<string, any> = {} const tableNamePrefixRef: Record<string, any> = {}
// TODO: find the upper bound / make it configurable
const maxSelectOptionsAllowed = 64
for (let i = 0; i < this.wb.SheetNames.length; i++) { for (let i = 0; i < this.wb.SheetNames.length; i++) {
const columnNamePrefixRef: Record<string, any> = { id: 0 } const columnNamePrefixRef: Record<string, any> = { id: 0 }
const sheet: any = this.wb.SheetNames[i] const sheet: any = this.wb.SheetNames[i]
@ -133,7 +137,6 @@ export default class ExcelTemplateAdapter extends TemplateGenerator {
meta: {}, meta: {},
} }
// const cellId = `${col.toString(26).split('').map(s => (parseInt(s, 26) + 10).toString(36).toUpperCase())}2`;
const cellId = this.xlsx.utils.encode_cell({ const cellId = this.xlsx.utils.encode_cell({
c: range.s.c + col, c: range.s.c + col,
r: columnNameRowExist, r: columnNameRowExist,
@ -141,11 +144,18 @@ export default class ExcelTemplateAdapter extends TemplateGenerator {
const cellProps = ws[cellId] || {} const cellProps = ws[cellId] || {}
column.uidt = excelTypeToUidt[cellProps.t] || UITypes.SingleLineText column.uidt = excelTypeToUidt[cellProps.t] || UITypes.SingleLineText
// todo: optimize
if (column.uidt === UITypes.SingleLineText) { if (column.uidt === UITypes.SingleLineText) {
// check for long text // check for long text
if (rows.some((r: any) => (r[col] || '').toString().match(/[\r\n]/) || (r[col] || '').toString().length > 255)) { if (isMultiLineTextType(rows)) {
column.uidt = UITypes.LongText column.uidt = UITypes.LongText
}
if (isEmailType(rows)) {
column.uidt = UITypes.Email
}
if (isUrlType(rows)) {
column.uidt = UITypes.URL
} else { } else {
const vals = rows const vals = rows
.slice(columnNameRowExist ? 1 : 0) .slice(columnNameRowExist ? 1 : 0)
@ -156,53 +166,8 @@ export default class ExcelTemplateAdapter extends TemplateGenerator {
if (checkboxType.length === 1) { if (checkboxType.length === 1) {
column.uidt = UITypes.Checkbox column.uidt = UITypes.Checkbox
} else { } else {
if (vals.some((v: any) => v && v.toString().includes(','))) { // Single Select / Multi Select
const flattenedVals = vals.flatMap((v: any) => Object.assign(column, extractMultiOrSingleSelectProps(vals))
v
? v
.toString()
.trim()
.split(/\s*,\s*/)
: [],
)
// 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 <a-select-option/> 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 {
// 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 <a-select-option/> 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("','")}'`
}
}
} }
} }
} else if (column.uidt === UITypes.Number) { } else if (column.uidt === UITypes.Number) {

41
packages/nc-gui/utils/parsers/JSONTemplateAdapter.ts

@ -1,13 +1,5 @@
import { UITypes } from 'nocodb-sdk' import { UITypes } from 'nocodb-sdk'
import { import { getCheckboxValue, getColumnUIDTAndMetas } from './parserHelpers'
extractMultiOrSingleSelectProps,
getCheckboxValue,
isCheckboxType,
isDecimalType,
isEmailType,
isMultiLineTextType,
isUrlType,
} from './parserHelpers'
import TemplateGenerator from './TemplateGenerator' import TemplateGenerator from './TemplateGenerator'
const jsonTypeToUidt: Record<string, string> = { const jsonTypeToUidt: Record<string, string> = {
@ -110,42 +102,13 @@ export default class JSONTemplateAdapter extends TemplateGenerator {
column.uidt = jsonTypeToUidt[typeof firstRowVal] || UITypes.SingleLineText column.uidt = jsonTypeToUidt[typeof firstRowVal] || UITypes.SingleLineText
const colData = jsonData.map((r: any) => extractNestedData(r, path)) const colData = jsonData.map((r: any) => extractNestedData(r, path))
Object.assign(column, this._getColumnUIDTAndMetas(colData, column.uidt)) Object.assign(column, getColumnUIDTAndMetas(colData, column.uidt))
columns.push(column) columns.push(column)
} }
return columns return columns
} }
_getColumnUIDTAndMetas(colData: any, defaultType: any) {
const colProps = { uidt: defaultType }
// todo: optimize
if (colProps.uidt === UITypes.SingleLineText) {
// check for long text
if (isMultiLineTextType(colData)) {
colProps.uidt = UITypes.LongText
}
if (isEmailType(colData)) {
colProps.uidt = UITypes.Email
}
if (isUrlType(colData)) {
colProps.uidt = UITypes.URL
} else {
const checkboxType = isCheckboxType(colData)
if (checkboxType.length === 1) {
colProps.uidt = UITypes.Checkbox
} else {
Object.assign(colProps, extractMultiOrSingleSelectProps(colData))
}
}
} else if (colProps.uidt === UITypes.Number) {
if (isDecimalType(colData)) {
colProps.uidt = UITypes.Decimal
}
}
return colProps
}
_parseTableData(tableMeta: any) { _parseTableData(tableMeta: any) {
for (const row of this.jsonData as any) { for (const row of this.jsonData as any) {
const rowData: any = {} const rowData: any = {}

70
packages/nc-gui/utils/parsers/parserHelpers.ts

@ -40,6 +40,7 @@ export const isCheckboxType: any = (values: [], col = null) => {
} }
return options return options
} }
export const getCheckboxValue = (value: number) => { export const getCheckboxValue = (value: number) => {
return value && aggBooleanOptions[value] return value && aggBooleanOptions[value]
} }
@ -51,6 +52,7 @@ export const isMultiLineTextType = (values: [], col = null) => {
} }
export const extractMultiOrSingleSelectProps = (colData: []) => { export const extractMultiOrSingleSelectProps = (colData: []) => {
const maxSelectOptionsAllowed = 64
const colProps: any = {} const colProps: any = {}
if (colData.some((v: any) => v && (v || '').toString().includes(','))) { if (colData.some((v: any) => v && (v || '').toString().includes(','))) {
let flattenedVals = colData.flatMap((v: any) => let flattenedVals = colData.flatMap((v: any) =>
@ -64,20 +66,40 @@ export const extractMultiOrSingleSelectProps = (colData: []) => {
const uniqueVals = (flattenedVals = flattenedVals.filter( const uniqueVals = (flattenedVals = flattenedVals.filter(
(v, i, arr) => i === arr.findIndex((v1) => v.toLowerCase() === v1.toLowerCase()), (v, i, arr) => i === arr.findIndex((v1) => v.toLowerCase() === v1.toLowerCase()),
)) ))
if (flattenedVals.length > uniqueVals.length && uniqueVals.length <= Math.ceil(flattenedVals.length / 2)) { if (uniqueVals.length > maxSelectOptionsAllowed) {
colProps.uidt = UITypes.MultiSelect // too many options are detected, convert the column to SingleLineText instead
colProps.uidt = UITypes.SingleLineText
// _disableSelect is used to disable the <a-select-option/> in TemplateEditor
colProps._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)) {
colProps.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
colProps.dtxp = `'${uniqueVals.join("','")}'` colProps.dtxp = `'${uniqueVals.join("','")}'`
} }
} else { } else {
const uniqueVals = colData const uniqueVals = [...new Set(colData.map((v: any) => v.toString().trim().toLowerCase()))]
.map((v: any) => (v || '').toString().trim())
.filter((v, i, arr) => i === arr.findIndex((v1) => v.toLowerCase() === v1.toLowerCase())) if (uniqueVals.length > maxSelectOptionsAllowed) {
if (colData.length > uniqueVals.length && uniqueVals.length <= Math.ceil(colData.length / 2)) { // too many options are detected, convert the column to SingleLineText instead
colProps.uidt = UITypes.SingleSelect colProps.uidt = UITypes.SingleLineText
// _disableSelect is used to disable the <a-select-option/> in TemplateEditor
colProps._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 (colData.length > uniqueVals.length && uniqueVals.length <= Math.ceil(colData.length / 2)) {
colProps.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
colProps.dtxp = `'${uniqueVals.join("','")}'` colProps.dtxp = `'${uniqueVals.join("','")}'`
} }
return colProps
} }
return colProps
} }
export const isDecimalType = (colData: []) => export const isDecimalType = (colData: []) =>
@ -89,7 +111,39 @@ export const isEmailType = (colData: []) =>
!colData.some((v: any) => { !colData.some((v: any) => {
return v && !isEmail(v) return v && !isEmail(v)
}) })
export const isUrlType = (colData: []) => export const isUrlType = (colData: []) =>
!colData.some((v: any) => { !colData.some((v: any) => {
return v && !isValidURL(v) return v && !isValidURL(v)
}) })
export const getColumnUIDTAndMetas = (colData: [], defaultType: string) => {
const colProps = { uidt: defaultType }
if (colProps.uidt === UITypes.SingleLineText) {
// check for long text
if (isMultiLineTextType(colData)) {
colProps.uidt = UITypes.LongText
}
if (isEmailType(colData)) {
colProps.uidt = UITypes.Email
}
if (isUrlType(colData)) {
colProps.uidt = UITypes.URL
} else {
const checkboxType = isCheckboxType(colData)
if (checkboxType.length === 1) {
colProps.uidt = UITypes.Checkbox
} else {
Object.assign(colProps, extractMultiOrSingleSelectProps(colData))
}
}
} else if (colProps.uidt === UITypes.Number) {
if (isDecimalType(colData)) {
colProps.uidt = UITypes.Decimal
}
}
// TODO: currency
// TODO: date / datetime
return colProps
}

Loading…
Cancel
Save