import { UITypes } from 'nocodb-sdk' import { isValidURL } from '~/utils/urlUtils' import { validateEmail } from '~/utils/validation' const booleanOptions = [ { checked: true, unchecked: false }, { 'x': true, '': false }, { yes: true, no: false }, { y: true, n: false }, { 1: true, 0: false }, { '[x]': true, '[]': false, '[ ]': false }, { '☑': true, '': false }, { '✅': true, '': false }, { '✓': true, '': false }, { '✔': true, '': false }, { enabled: true, disabled: false }, { on: true, off: false }, { 'done': true, '': false }, { true: true, false: false }, ] const aggBooleanOptions: any = booleanOptions.reduce((obj, o) => ({ ...obj, ...o }), {}) const getColVal = (row: any, col?: number) => { return row && col !== undefined ? row[col] : row } export const isCheckboxType: any = (values: [], col?: number) => { let options = booleanOptions for (let i = 0; i < values.length; i++) { const val = getColVal(values[i], col) if (val === null || val === undefined || val.toString().trim() === '') { continue } options = options.filter((v) => val in v) if (!options.length) { return false } } return options } export const getCheckboxValue = (value: any) => { return value && aggBooleanOptions[value] } export const isMultiLineTextType = (values: [], col?: number) => { return values.some( (r) => (getColVal(r, col) || '').toString().match(/[\r\n]/) || (getColVal(r, col) || '').toString().length > 255, ) } export const extractMultiOrSingleSelectProps = (colData: []) => { const maxSelectOptionsAllowed = 64 const colProps: any = {} if (colData.some((v: any) => v && (v || '').toString().includes(','))) { const flattenedVals = colData.flatMap((v: any) => v ? v .toString() .trim() .split(/\s*,\s*/) : [], ) const uniqueVals = [...new Set(flattenedVals.map((v: any) => v.toString().trim()))] if (uniqueVals.length > maxSelectOptionsAllowed) { // too many options are detected, convert the column to SingleLineText instead colProps.uidt = UITypes.SingleLineText // _disableSelect is used to disable the 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.map((v) => `'${v.replace(/'/gi, "''")}'`).join(',')}` } } else { const uniqueVals = [...new Set(colData.map((v: any) => v.toString().trim()))] if (uniqueVals.length > maxSelectOptionsAllowed) { // too many options are detected, convert the column to SingleLineText instead colProps.uidt = UITypes.SingleLineText // _disableSelect is used to disable the 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.map((v) => `'${v.replace(/'/gi, "''")}'`).join(',')}` } return colProps } } export const isDecimalType = (colData: []) => colData.some((v: any) => { return v && parseInt(v) !== +v }) export const isEmailType = (colData: [], col?: number) => colData.some((r: any) => { const v = getColVal(r, col) return v && validateEmail(v) }) export const isUrlType = (colData: [], col?: number) => colData.some((r: any) => { const v = getColVal(r, col) 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(import): currency // TODO(import): date / datetime return colProps }