mirror of https://github.com/nocodb/nocodb
Pranav C
2 years ago
6 changed files with 650 additions and 3 deletions
@ -0,0 +1,436 @@ |
|||||||
|
<template> |
||||||
|
<div :class="{'pt-10':!hideLabel}"> |
||||||
|
<v-dialog v-model="dropOrUpload" max-width="600"> |
||||||
|
<v-card max-width="600"> |
||||||
|
<v-tabs height="30" :value="2"> |
||||||
|
<v-tab> |
||||||
|
<v-icon small class="mr-1"> |
||||||
|
mdi-file-upload-outline |
||||||
|
</v-icon> |
||||||
|
<span class="caption text-capitalize">Upload</span> |
||||||
|
</v-tab> |
||||||
|
<v-tab> |
||||||
|
<v-icon small class="mr-1"> |
||||||
|
mdi-link-variant |
||||||
|
</v-icon> |
||||||
|
<span class="caption text-capitalize">URL</span> |
||||||
|
</v-tab> |
||||||
|
<v-tab> |
||||||
|
<v-icon small class="mr-1"> |
||||||
|
mdi-link-variant |
||||||
|
</v-icon> |
||||||
|
<span class="caption text-capitalize">String</span> |
||||||
|
</v-tab> |
||||||
|
|
||||||
|
<v-tab-item> |
||||||
|
<div class="nc-excel-import-tab-item "> |
||||||
|
<div |
||||||
|
class="nc-droppable d-flex align-center justify-center flex-column" |
||||||
|
:style="{ |
||||||
|
background : dragOver ? '#7772' : '' |
||||||
|
}" |
||||||
|
@click="$refs.file.click()" |
||||||
|
@drop.prevent="dropHandler" |
||||||
|
@dragover.prevent="dragOver = true" |
||||||
|
@dragenter.prevent="dragOver = true" |
||||||
|
@dragexit="dragOver = false" |
||||||
|
@dragleave="dragOver = false" |
||||||
|
@dragend="dragOver = false" |
||||||
|
> |
||||||
|
<x-icon :color="['primary','grey']" size="50"> |
||||||
|
mdi-file-plus-outline |
||||||
|
</x-icon> |
||||||
|
<p class="title mb-1 mt-2"> |
||||||
|
<!-- Select File to Upload--> |
||||||
|
{{ $t('msg.info.upload') }} |
||||||
|
</p> |
||||||
|
<p class="grey--text mb-1"> |
||||||
|
<!-- or drag and drop file--> |
||||||
|
{{ $t('msg.info.upload_sub') }} |
||||||
|
</p> |
||||||
|
|
||||||
|
<p v-if="quickImportType == 'excel'" class="caption grey--text"> |
||||||
|
<!-- Supported: .xls, .xlsx, .xlsm, .ods, .ots --> |
||||||
|
{{ $t('msg.info.excelSupport') }} |
||||||
|
</p> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</v-tab-item> |
||||||
|
<v-tab-item> |
||||||
|
<div class="nc-excel-import-tab-item align-center"> |
||||||
|
<div class="pa-4 d-100 h-100"> |
||||||
|
<v-form ref="form" v-model="valid"> |
||||||
|
<div class="d-flex"> |
||||||
|
<!--label="Enter excel file url"--> |
||||||
|
<v-text-field |
||||||
|
v-model="url" |
||||||
|
hide-details="auto" |
||||||
|
type="url" |
||||||
|
:label="quickImportType == 'excel' ? $t('msg.info.excelURL') : $t('msg.info.csvURL') " |
||||||
|
class="caption" |
||||||
|
outlined |
||||||
|
dense |
||||||
|
:rules="[v => !!v || $t('general.required') ]" |
||||||
|
/> |
||||||
|
<v-btn v-t="['c:project:create:excel:load-url']" class="ml-3" color="primary" @click="loadUrl"> |
||||||
|
<!--Load--> |
||||||
|
{{ $t('general.load') }} |
||||||
|
</v-btn> |
||||||
|
</div> |
||||||
|
</v-form> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</v-tab-item> |
||||||
|
<v-tab-item> |
||||||
|
<div class="nc-excel-import-tab-item align-center"> |
||||||
|
<div class="pa-4 d-100 h-100"> |
||||||
|
<v-form ref="form" v-model="valid"> |
||||||
|
<div class=""> |
||||||
|
<!--label="Enter excel file url"--> |
||||||
|
<monaco-json-editor |
||||||
|
v-model="jsonString" |
||||||
|
style="height:300px" |
||||||
|
/> |
||||||
|
<v-btn v-t="['c:project:create:excel:load-url']" class="ml-3" color="primary" @click="loadJsonString"> |
||||||
|
<!--Load--> |
||||||
|
{{ $t('general.load') }} |
||||||
|
</v-btn> |
||||||
|
</div> |
||||||
|
</v-form> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</v-tab-item> |
||||||
|
</v-tabs> |
||||||
|
|
||||||
|
<div class="px-4 pb-2"> |
||||||
|
<div class="d-flex"> |
||||||
|
<v-spacer /> |
||||||
|
<span class="caption pointer grey--text" @click="showMore = !showMore"> |
||||||
|
{{ showMore ? $t('general.hideAll') : $t('general.showMore') }} |
||||||
|
<v-icon small color="grey lighten-1">mdi-menu-{{ showMore ? 'up' : 'down' }}</v-icon> |
||||||
|
</span> |
||||||
|
</div> |
||||||
|
<div class="mb-2 pt-2 nc-excel-import-options" :style="{ maxHeight: showMore ? '100px' : '0'}"> |
||||||
|
<p /> |
||||||
|
<!--hint="# of rows to parse to infer data type"--> |
||||||
|
<v-text-field |
||||||
|
v-model="parserConfig.maxRowsToParse" |
||||||
|
style="max-width: 250px" |
||||||
|
class="caption mx-auto" |
||||||
|
dense |
||||||
|
persistent-hint |
||||||
|
:hint="$t('msg.info.footMsg')" |
||||||
|
outlined |
||||||
|
type="number" |
||||||
|
/> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</v-card> |
||||||
|
</v-dialog> |
||||||
|
|
||||||
|
<v-tooltip bottom> |
||||||
|
<template #activator="{on}"> |
||||||
|
<input |
||||||
|
v-if="quickImportType == 'excel'" |
||||||
|
ref="file" |
||||||
|
class="nc-excel-import-input" |
||||||
|
type="file" |
||||||
|
style="display: none" |
||||||
|
accept=".xlsx, .xls, .xlsm, .ods, .ots" |
||||||
|
@change="_change($event)" |
||||||
|
> |
||||||
|
<input |
||||||
|
v-if="quickImportType == 'csv'" |
||||||
|
ref="file" |
||||||
|
class="nc-excel-import-input" |
||||||
|
type="file" |
||||||
|
style="display: none" |
||||||
|
accept=".csv" |
||||||
|
@change="_change($event)" |
||||||
|
> |
||||||
|
<v-btn |
||||||
|
|
||||||
|
v-if="!hideLabel" |
||||||
|
small |
||||||
|
outlined |
||||||
|
v-on="on" |
||||||
|
@click="$refs.file.click()" |
||||||
|
> |
||||||
|
<v-icon small class="mr-1"> |
||||||
|
mdi-file-excel-outline |
||||||
|
</v-icon> |
||||||
|
<!--Import--> |
||||||
|
{{ $t('activity.import') }} |
||||||
|
</v-btn> |
||||||
|
</template> |
||||||
|
<span class="caption">Create template from Excel</span> |
||||||
|
</v-tooltip> |
||||||
|
|
||||||
|
<v-dialog v-if="templateData" v-model="templateEditorModal" max-width="1000"> |
||||||
|
<v-card class="pa-6" min-width="500"> |
||||||
|
<template-editor :project-template.sync="templateData" excel-import :quick-import-type="quickImportType"> |
||||||
|
<template #toolbar="{valid}"> |
||||||
|
<h3 class="mt-2 grey--text"> |
||||||
|
<span> |
||||||
|
JSON |
||||||
|
</span> |
||||||
|
: {{ templateData.title }} |
||||||
|
</h3> |
||||||
|
<v-spacer /> |
||||||
|
<v-spacer /> |
||||||
|
<create-project-from-template-btn |
||||||
|
:template-data="templateData" |
||||||
|
:import-data="importData" |
||||||
|
:import-to-project="importToProject" |
||||||
|
excel-import |
||||||
|
:valid="valid" |
||||||
|
create-gql-text="Import as GQL Project" |
||||||
|
create-rest-text="Import as REST Project" |
||||||
|
@closeModal="$emit('closeModal'),templateEditorModal = false" |
||||||
|
> |
||||||
|
<!--Import Excel--> |
||||||
|
<span v-if="quickImportType === 'excel'"> |
||||||
|
{{ $t('activity.importExcel') }} |
||||||
|
</span> |
||||||
|
<!--Import CSV--> |
||||||
|
<span v-if="quickImportType === 'csv'"> |
||||||
|
{{ $t('activity.importCSV') }} |
||||||
|
</span> |
||||||
|
</create-project-from-template-btn> |
||||||
|
</template> |
||||||
|
</template-editor> |
||||||
|
</v-card> |
||||||
|
</v-dialog> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script> |
||||||
|
|
||||||
|
// import XLSX from 'xlsx' |
||||||
|
import TemplateEditor from '~/components/templates/Editor' |
||||||
|
import CreateProjectFromTemplateBtn from '~/components/templates/CreateProjectFromTemplateBtn' |
||||||
|
import ExcelUrlTemplateAdapter from '~/components/import/templateParsers/ExcelUrlTemplateAdapter' |
||||||
|
import ExcelTemplateAdapter from '~/components/import/templateParsers/ExcelTemplateAdapter' |
||||||
|
import MonacoJsonEditor from '~/components/monaco/MonacoJsonEditor' |
||||||
|
import JSONTemplateAdapter from '~/components/import/templateParsers/JSONTemplateAdapter' |
||||||
|
|
||||||
|
export default { |
||||||
|
name: 'JsonImport', |
||||||
|
components: { MonacoJsonEditor, CreateProjectFromTemplateBtn, TemplateEditor }, |
||||||
|
props: { |
||||||
|
hideLabel: Boolean, |
||||||
|
value: Boolean, |
||||||
|
importToProject: Boolean, |
||||||
|
quickImportType: String |
||||||
|
}, |
||||||
|
data() { |
||||||
|
return { |
||||||
|
templateEditorModal: false, |
||||||
|
valid: null, |
||||||
|
templateData: null, |
||||||
|
importData: null, |
||||||
|
dragOver: false, |
||||||
|
url: '', |
||||||
|
showMore: false, |
||||||
|
parserConfig: { |
||||||
|
maxRowsToParse: 500 |
||||||
|
}, |
||||||
|
filename: '', |
||||||
|
jsonString: `[{ |
||||||
|
"data": "Click Here", |
||||||
|
"size": 36, |
||||||
|
"style": "bold", |
||||||
|
"name": "text1", |
||||||
|
"hOffset": 250, |
||||||
|
"vOffset": 100, |
||||||
|
"alignment": "center", |
||||||
|
"onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;" |
||||||
|
}]` |
||||||
|
} |
||||||
|
}, |
||||||
|
computed: { |
||||||
|
dropOrUpload: { |
||||||
|
set(v) { |
||||||
|
this.$emit('input', v) |
||||||
|
}, |
||||||
|
get() { |
||||||
|
return this.value |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
mounted() { |
||||||
|
if (this.$route && this.$route.query && this.$route.query.excelUrl) { |
||||||
|
this.url = this.$route.query.excelUrl |
||||||
|
this.loadUrl() |
||||||
|
} |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
|
||||||
|
selectFile() { |
||||||
|
this.$refs.file.files = null |
||||||
|
this.$refs.file.click() |
||||||
|
}, |
||||||
|
|
||||||
|
_change(event) { |
||||||
|
const files = event.target.files |
||||||
|
if (files && files[0]) { |
||||||
|
this._file(files[0]) |
||||||
|
event.target.value = '' |
||||||
|
} |
||||||
|
}, |
||||||
|
async _file(file) { |
||||||
|
this.templateData = null |
||||||
|
this.importData = null |
||||||
|
this.$store.commit('loader/MutMessage', 'Loading excel file') |
||||||
|
let i = 0 |
||||||
|
const int = setInterval(() => { |
||||||
|
this.$store.commit('loader/MutMessage', `Loading excel file${'.'.repeat(++i % 4)}`) |
||||||
|
}, 1000) |
||||||
|
this.dropOrUpload = false |
||||||
|
const reader = new FileReader() |
||||||
|
this.filename = file.name |
||||||
|
|
||||||
|
reader.onload = async(e) => { |
||||||
|
const ab = e.target.result |
||||||
|
await this.parseAndExtractData('file', ab, file.name) |
||||||
|
this.$store.commit('loader/MutMessage', null) |
||||||
|
|
||||||
|
clearInterval(int) |
||||||
|
} |
||||||
|
|
||||||
|
const handleEvent = (event) => { |
||||||
|
this.$store.commit('loader/MutMessage', `${event.type}: ${event.loaded} bytes transferred`) |
||||||
|
} |
||||||
|
|
||||||
|
reader.addEventListener('progress', handleEvent) |
||||||
|
reader.onerror = (e) => { |
||||||
|
console.log('error', e) |
||||||
|
this.$store.commit('loader/MutClear') |
||||||
|
} |
||||||
|
reader.readAsArrayBuffer(file) |
||||||
|
}, |
||||||
|
|
||||||
|
async parseAndExtractData(type, val, name) { |
||||||
|
try { |
||||||
|
let templateGenerator |
||||||
|
this.templateData = null |
||||||
|
this.importData = null |
||||||
|
switch (type) { |
||||||
|
case 'file': |
||||||
|
templateGenerator = new ExcelTemplateAdapter(name, val, this.parserConfig) |
||||||
|
break |
||||||
|
case 'url': |
||||||
|
templateGenerator = new ExcelUrlTemplateAdapter(val, this.$store, this.parserConfig, this.$api) |
||||||
|
break |
||||||
|
case 'string': |
||||||
|
templateGenerator = new JSONTemplateAdapter('test', val) |
||||||
|
break |
||||||
|
} |
||||||
|
await templateGenerator.init() |
||||||
|
templateGenerator.parse() |
||||||
|
this.templateData = templateGenerator.getTemplate() |
||||||
|
this.importData = templateGenerator.getData() |
||||||
|
this.templateEditorModal = true |
||||||
|
} catch (e) { |
||||||
|
console.log(e) |
||||||
|
this.$toast |
||||||
|
.error(await this._extractSdkResponseErrorMsg(e)) |
||||||
|
.goAway(3000) |
||||||
|
} |
||||||
|
}, |
||||||
|
|
||||||
|
dropHandler(ev) { |
||||||
|
this.dragOver = false |
||||||
|
let file |
||||||
|
if (ev.dataTransfer.items) { |
||||||
|
// Use DataTransferItemList interface to access the file(s) |
||||||
|
if (ev.dataTransfer.items.length && ev.dataTransfer.items[0].kind === 'file') { |
||||||
|
file = ev.dataTransfer.items[0].getAsFile() |
||||||
|
} |
||||||
|
} else if (ev.dataTransfer.files.length) { |
||||||
|
file = ev.dataTransfer.files[0] |
||||||
|
} |
||||||
|
|
||||||
|
if (!file) { |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
if (this.quickImportType === 'excel') { |
||||||
|
if (!/.*\.(xls|xlsx|xlsm|ods|ots)/.test(file.name)) { |
||||||
|
return this.$toast.error('Dropped file is not an accepted file type. The accepted file types are .xls, .xlsx, .xlsm, .ods, .ots!').goAway(3000) |
||||||
|
} |
||||||
|
} else if (this.quickImportType === 'csv') { |
||||||
|
if (!/.*\.(csv)/.test(file.name)) { |
||||||
|
return this.$toast.error('Dropped file is not an accepted file type. The accepted file type is .csv!').goAway(3000) |
||||||
|
} |
||||||
|
} |
||||||
|
this._file(file) |
||||||
|
}, |
||||||
|
dragOverHandler(ev) { |
||||||
|
// Prevent default behavior (Prevent file from being opened) |
||||||
|
ev.preventDefault() |
||||||
|
}, |
||||||
|
|
||||||
|
async loadUrl() { |
||||||
|
if ((this.$refs.form && !this.$refs.form.validate()) || !this.url) { |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
this.$store.commit('loader/MutMessage', 'Loading excel file from url') |
||||||
|
|
||||||
|
let i = 0 |
||||||
|
const int = setInterval(() => { |
||||||
|
this.$store.commit('loader/MutMessage', `Loading excel file${'.'.repeat(++i % 4)}`) |
||||||
|
}, 1000) |
||||||
|
|
||||||
|
this.dropOrUpload = false |
||||||
|
|
||||||
|
await this.parseAndExtractData('url', this.url, '') |
||||||
|
clearInterval(int) |
||||||
|
this.$store.commit('loader/MutClear') |
||||||
|
}, |
||||||
|
|
||||||
|
async loadJsonString() { |
||||||
|
// if ((this.$refs.form && !this.$refs.form.validate()) || !this.url) { |
||||||
|
// return |
||||||
|
// } |
||||||
|
|
||||||
|
this.$store.commit('loader/MutMessage', 'Loading excel file from url') |
||||||
|
|
||||||
|
let i = 0 |
||||||
|
const int = setInterval(() => { |
||||||
|
this.$store.commit('loader/MutMessage', `Loading excel file${'.'.repeat(++i % 4)}`) |
||||||
|
}, 1000) |
||||||
|
|
||||||
|
this.dropOrUpload = false |
||||||
|
|
||||||
|
await this.parseAndExtractData('string', this.jsonString) |
||||||
|
clearInterval(int) |
||||||
|
this.$store.commit('loader/MutClear') |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style scoped> |
||||||
|
.nc-droppable { |
||||||
|
width: 100%; |
||||||
|
min-height: 200px; |
||||||
|
border-radius: 4px; |
||||||
|
border: 2px dashed #ddd; |
||||||
|
} |
||||||
|
|
||||||
|
.nc-excel-import-tab-item { |
||||||
|
min-height: 400px; |
||||||
|
padding: 20px; |
||||||
|
display: flex; |
||||||
|
align-items: stretch; |
||||||
|
width: 100%; |
||||||
|
} |
||||||
|
|
||||||
|
.nc-excel-import-options { |
||||||
|
transition: .4s max-height; |
||||||
|
overflow: hidden; |
||||||
|
} |
||||||
|
</style> |
@ -0,0 +1,156 @@ |
|||||||
|
import { TemplateGenerator } from 'nocodb-sdk' |
||||||
|
import { UITypes } from '~/components/project/spreadsheet/helpers/uiTypes' |
||||||
|
import { getCheckboxValue, isCheckboxType } from '~/components/import/templateParsers/parserHelpers' |
||||||
|
|
||||||
|
const jsonTypeToUidt = { |
||||||
|
number: UITypes.Number, |
||||||
|
string: UITypes.SingleLineText, |
||||||
|
date: UITypes.DateTime, |
||||||
|
boolean: UITypes.Checkbox, |
||||||
|
object: UITypes.LongText |
||||||
|
} |
||||||
|
|
||||||
|
export default class JSONTemplateAdapter extends TemplateGenerator { |
||||||
|
constructor(name = 'test', data, parserConfig = {}) { |
||||||
|
super() |
||||||
|
this.config = { |
||||||
|
maxRowsToParse: 500, |
||||||
|
...parserConfig |
||||||
|
} |
||||||
|
this.name = name |
||||||
|
this.jsonData = typeof data === 'string' ? JSON.parse(data) : data |
||||||
|
this.project = { |
||||||
|
title: this.name, |
||||||
|
tables: [] |
||||||
|
} |
||||||
|
this.data = {} |
||||||
|
} |
||||||
|
|
||||||
|
async init() { |
||||||
|
} |
||||||
|
|
||||||
|
parseData() { |
||||||
|
this.columns = this.csv.meta.fields |
||||||
|
this.data = this.csv.data |
||||||
|
} |
||||||
|
|
||||||
|
getColumns() { |
||||||
|
return this.columns |
||||||
|
} |
||||||
|
|
||||||
|
getData() { |
||||||
|
return this.data |
||||||
|
} |
||||||
|
|
||||||
|
parse() { |
||||||
|
// for (let i = 0; i < this.wb.SheetNames.length; i++) {
|
||||||
|
// const columnNamePrefixRef = { id: 0 }
|
||||||
|
|
||||||
|
const tn = 'table' |
||||||
|
|
||||||
|
const table = { table_name: tn, ref_table_name: tn, columns: [] } |
||||||
|
|
||||||
|
this.data[tn] = [] |
||||||
|
|
||||||
|
// const ws = this.wb.Sheets[sheet]
|
||||||
|
// const range = XLSX.utils.decode_range(ws['!ref'])
|
||||||
|
// const rows = XLSX.utils.sheet_to_json(ws, { header: 1, blankrows: false, cellDates: true, defval: null })
|
||||||
|
|
||||||
|
const objKeys = Object.keys(this.jsonData[0]) |
||||||
|
|
||||||
|
for (let col = 0; col < objKeys.length; col++) { |
||||||
|
const key = objKeys[col] |
||||||
|
const cn = objKeys[col].replace(/\W/g, '_').trim() |
||||||
|
|
||||||
|
const column = { |
||||||
|
column_name: cn, |
||||||
|
ref_column_name: cn |
||||||
|
} |
||||||
|
|
||||||
|
table.columns.push(column) |
||||||
|
|
||||||
|
column.uidt = jsonTypeToUidt[typeof this.jsonData[0][key]] || UITypes.SingleLineText |
||||||
|
|
||||||
|
// todo: optimize
|
||||||
|
if (column.uidt === UITypes.SingleLineText) { |
||||||
|
// check for long text
|
||||||
|
if (this.jsonData.some(r => |
||||||
|
(r[key] || '').toString().match(/[\r\n]/) || |
||||||
|
(r[key] || '').toString().length > 255) |
||||||
|
) { |
||||||
|
column.uidt = UITypes.LongText |
||||||
|
} else { |
||||||
|
const vals = this.jsonData |
||||||
|
.map(r => r[key]) |
||||||
|
.filter(v => v !== null && v !== undefined && v.toString().trim() !== '') |
||||||
|
|
||||||
|
const checkboxType = isCheckboxType(vals) |
||||||
|
if (checkboxType.length === 1) { |
||||||
|
column.uidt = UITypes.Checkbox |
||||||
|
} else { |
||||||
|
// todo: optimize
|
||||||
|
// check column is multi or single select by comparing unique values
|
||||||
|
// todo:
|
||||||
|
// eslint-disable-next-line no-lonely-if
|
||||||
|
if (vals.some(v => v && v.toString().includes(','))) { |
||||||
|
let flattenedVals = vals.flatMap(v => v ? v.toString().trim().split(/\s*,\s*/) : []) |
||||||
|
const uniqueVals = flattenedVals = flattenedVals |
||||||
|
.filter((v, i, arr) => i === arr.findIndex(v1 => v.toLowerCase() === v1.toLowerCase())) |
||||||
|
if (flattenedVals.length > uniqueVals.length && uniqueVals.length <= Math.ceil(flattenedVals.length / 2)) { |
||||||
|
column.uidt = UITypes.MultiSelect |
||||||
|
column.dtxp = `'${uniqueVals.join("','")}'` |
||||||
|
} |
||||||
|
} else { |
||||||
|
const uniqueVals = vals.map(v => v.toString().trim()).filter((v, i, arr) => i === arr.findIndex(v1 => v.toLowerCase() === v1.toLowerCase())) |
||||||
|
if (vals.length > uniqueVals.length && uniqueVals.length <= Math.ceil(vals.length / 2)) { |
||||||
|
column.uidt = UITypes.SingleSelect |
||||||
|
column.dtxp = `'${uniqueVals.join("','")}'` |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} else if (column.uidt === UITypes.Number) { |
||||||
|
if (this.jsonData.slice(1, this.config.maxRowsToParse).some((v) => { |
||||||
|
return v && v[key] && parseInt(+v[key]) !== +v[key] |
||||||
|
})) { |
||||||
|
column.uidt = UITypes.Decimal |
||||||
|
} |
||||||
|
if (this.jsonData.every((v, i) => { |
||||||
|
return v[key] && v[key].toString().startsWith('$') |
||||||
|
})) { |
||||||
|
column.uidt = UITypes.Currency |
||||||
|
} |
||||||
|
} else if (column.uidt === UITypes.DateTime) { |
||||||
|
if (this.jsonData.every((v, i) => { |
||||||
|
return v[key] && v[key].toString().split(' ').length === 1 |
||||||
|
})) { |
||||||
|
column.uidt = UITypes.Date |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// let rowIndex = 0
|
||||||
|
for (const row of this.jsonData) { |
||||||
|
const rowData = {} |
||||||
|
for (let i = 0; i < table.columns.length; i++) { |
||||||
|
if (table.columns[i].uidt === UITypes.Checkbox) { |
||||||
|
rowData[table.columns[i].column_name] = getCheckboxValue(row[i]) |
||||||
|
} else if (table.columns[i].uidt === UITypes.Currency) { |
||||||
|
rowData[table.columns[i].column_name] = (row[table.columns[i].ref_column_name].replace(/[^\d.]+/g, '')) || row[i] |
||||||
|
} else if (table.columns[i].uidt === UITypes.SingleSelect || table.columns[i].uidt === UITypes.MultiSelect) { |
||||||
|
rowData[table.columns[i].column_name] = (row[table.columns[i].ref_column_name] || '').toString().trim() || null |
||||||
|
} else { |
||||||
|
// toto: do parsing if necessary based on type
|
||||||
|
rowData[table.columns[i].column_name] = row[table.columns[i].ref_column_name] |
||||||
|
} |
||||||
|
} |
||||||
|
this.data[tn].push(rowData) |
||||||
|
// rowIndex++
|
||||||
|
} |
||||||
|
this.project.tables.push(table) |
||||||
|
} |
||||||
|
|
||||||
|
getTemplate() { |
||||||
|
return this.project |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,30 @@ |
|||||||
|
import UITypes from './UITypes'; |
||||||
|
|
||||||
|
export interface Column { |
||||||
|
column_name: string; |
||||||
|
ref_column_name: string; |
||||||
|
uidt?: UITypes; |
||||||
|
dtxp?: any; |
||||||
|
dt?: any; |
||||||
|
} |
||||||
|
export interface Table { |
||||||
|
table_name: string; |
||||||
|
ref_table_name: string; |
||||||
|
columns: Array<Column>; |
||||||
|
} |
||||||
|
export interface Template { |
||||||
|
title: string; |
||||||
|
tables: Array<Table>; |
||||||
|
} |
||||||
|
|
||||||
|
export default abstract class TemplateGenerator { |
||||||
|
abstract parse(): Promise<any>; |
||||||
|
abstract parseTemplate(): Promise<Template>; |
||||||
|
abstract getColumns(): Promise<any>; |
||||||
|
abstract parseData(): Promise<any>; |
||||||
|
abstract getData(): Promise<{ |
||||||
|
[table_name: string]: Array<{ |
||||||
|
[key: string]: any; |
||||||
|
}>; |
||||||
|
}>; |
||||||
|
} |
Loading…
Reference in new issue