diff --git a/packages/nc-gui/components/import/dropOrSelectFile.vue b/packages/nc-gui/components/import/dropOrSelectFile.vue
new file mode 100644
index 0000000000..d9ec39d271
--- /dev/null
+++ b/packages/nc-gui/components/import/dropOrSelectFile.vue
@@ -0,0 +1,105 @@
+
+
+
+
+ mdi-file-plus-outline
+
+
+ Select {{ text }} file to Upload
+
+
+ or drag and drop {{ text }} file
+
+
+
+
+
+
+
+
+
diff --git a/packages/nc-gui/components/import/dropOrSelectFileModal.vue b/packages/nc-gui/components/import/dropOrSelectFileModal.vue
index 2f90b5207e..7f24221cdc 100644
--- a/packages/nc-gui/components/import/dropOrSelectFileModal.vue
+++ b/packages/nc-gui/components/import/dropOrSelectFileModal.vue
@@ -1,47 +1,55 @@
-
-
-
- mdi-file-plus-outline
-
-
- Select {{ text }} file to Upload
-
-
- or drag and drop {{ text }} file
-
-
-
-
+
+
diff --git a/packages/nc-gui/components/import/excelImport.vue b/packages/nc-gui/components/import/excelImport.vue
index 2229564fbb..facfe7560c 100644
--- a/packages/nc-gui/components/import/excelImport.vue
+++ b/packages/nc-gui/components/import/excelImport.vue
@@ -2,31 +2,81 @@
-
-
-
- mdi-file-plus-outline
+
+
+
+ mdi-file-upload-outline
-
- Select Files to Upload
-
-
- or drag and drop files
-
-
-
+ Upload
+
+
+
+ mdi-link-variant
+
+ URL
+
+
+
+
+
+
+ mdi-file-plus-outline
+
+
+ Select File to Upload
+
+
+ or drag and drop file
+
+
+
+ Supported: .xls, .xlsx, .xlsm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -37,7 +87,7 @@
class="nc-excel-import-input"
type="file"
style="display: none"
- accept=".xlsx, .xls"
+ accept=".xlsx, .xls, .xlsm"
@change="_change($event)"
>
-
+
// import XLSX from 'xlsx'
-import ExcelTemplateAdapter from '~/components/import/ExcelTemplateAdapter'
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'
export default {
name: 'ExcelImport',
@@ -108,11 +159,13 @@ export default {
},
data() {
return {
+ valid: null,
templateData: null,
importData: null,
dragOver: false,
loaderMessage: null,
- progress: null
+ progress: null,
+ url: ''
}
},
computed: {
@@ -150,12 +203,9 @@ export default {
this.dropOrUpload = false
const reader = new FileReader()
- reader.onload = (e) => {
+ reader.onload = async(e) => {
const ab = e.target.result
- const templateGenerator = new ExcelTemplateAdapter(file.name, ab)
- templateGenerator.parse()
- this.templateData = templateGenerator.getTemplate()
- this.importData = templateGenerator.getData()
+ await this.parseAndExtractData('file', ab, file.name)
this.loaderMessage = null
clearInterval(int)
}
@@ -170,6 +220,23 @@ export default {
}
reader.readAsArrayBuffer(file)
},
+
+ async parseAndExtractData(type, val, name) {
+ let templateGenerator
+ switch (type) {
+ case 'file':
+ templateGenerator = new ExcelTemplateAdapter(name, val)
+ break
+ case 'url':
+ templateGenerator = new ExcelUrlTemplateAdapter(val, this.$store)
+ break
+ }
+ await templateGenerator.init()
+ templateGenerator.parse()
+ this.templateData = templateGenerator.getTemplate()
+ this.importData = templateGenerator.getData()
+ },
+
dropHandler(ev) {
console.log('File(s) dropped')
let file
@@ -194,6 +261,22 @@ export default {
// Prevent default behavior (Prevent file from being opened)
ev.preventDefault()
+ },
+
+ async loadUrl() {
+ if (!this.$refs.form.validate()) { return }
+
+ this.loaderMessage = 'Loading excel file from url'
+ let i = 0
+ const int = setInterval(() => {
+ this.loaderMessage = `Loading excel file${'.'.repeat(++i % 4)}`
+ }, 1000)
+
+ this.dropOrUpload = false
+
+ await this.parseAndExtractData('url', this.url, '')
+ clearInterval(int)
+ this.loaderMessage = null
}
}
@@ -205,6 +288,14 @@ export default {
width: 100%;
min-height: 200px;
border-radius: 4px;
- border: 2px dashed var(--v-textColor-lighten5);
+ border: 2px dashed #ddd;
+}
+
+.nc-excel-import-tab-item{
+ min-height: 400px;
+ padding: 20px;
+ display: flex;
+ align-items: stretch;
+width:100%;
}
diff --git a/packages/nc-gui/components/import/CSVTemplateAdapter.js b/packages/nc-gui/components/import/templateParsers/CSVTemplateAdapter.js
similarity index 68%
rename from packages/nc-gui/components/import/CSVTemplateAdapter.js
rename to packages/nc-gui/components/import/templateParsers/CSVTemplateAdapter.js
index a721f6261d..9a3be0d4de 100644
--- a/packages/nc-gui/components/import/CSVTemplateAdapter.js
+++ b/packages/nc-gui/components/import/templateParsers/CSVTemplateAdapter.js
@@ -1,11 +1,11 @@
import Papaparse from 'papaparse'
-import TemplateGenerator from '~/components/import/TemplateGenerator'
+import TemplateGenerator from '~/components/import/templateParsers/TemplateGenerator'
export default class CSVTemplateAdapter extends TemplateGenerator {
constructor(name, data) {
super()
this.name = name
- this.csv = Papaparse.parse(data, { header: true })
+ this.csvData = data
this.project = {
title: this.name,
tables: []
@@ -13,6 +13,10 @@ export default class CSVTemplateAdapter extends TemplateGenerator {
this.data = {}
}
+ async init() {
+ this.csv = Papaparse.parse(this.csvData, { header: true })
+ }
+
parseData() {
this.columns = this.csv.meta.fields
this.data = this.csv.data
diff --git a/packages/nc-gui/components/import/ExcelTemplateAdapter.js b/packages/nc-gui/components/import/templateParsers/ExcelTemplateAdapter.js
similarity index 83%
rename from packages/nc-gui/components/import/ExcelTemplateAdapter.js
rename to packages/nc-gui/components/import/templateParsers/ExcelTemplateAdapter.js
index 0a16b2fe67..2c14dcc3bf 100644
--- a/packages/nc-gui/components/import/ExcelTemplateAdapter.js
+++ b/packages/nc-gui/components/import/templateParsers/ExcelTemplateAdapter.js
@@ -1,6 +1,6 @@
import XLSX from 'xlsx'
-import TemplateGenerator from '~/components/import/TemplateGenerator'
import { UITypes } from '~/components/project/spreadsheet/helpers/uiTypes'
+import TemplateGenerator from '~/components/import/templateParsers/TemplateGenerator'
const excelTypeToUidt = {
d: UITypes.DateTime,
@@ -13,7 +13,7 @@ export default class ExcelTemplateAdapter extends TemplateGenerator {
constructor(name, ab) {
super()
this.name = name
- this.wb = XLSX.read(new Uint8Array(ab), { type: 'array' })
+ this.excelData = ab
this.project = {
title: this.name,
tables: []
@@ -21,6 +21,10 @@ export default class ExcelTemplateAdapter extends TemplateGenerator {
this.data = {}
}
+ async init() {
+ this.wb = XLSX.read(new Uint8Array(this.excelData), { type: 'array' })
+ }
+
parse() {
for (let i = 0; i < this.wb.SheetNames.length; i++) {
const sheet = this.wb.SheetNames[i]
@@ -31,10 +35,10 @@ export default class ExcelTemplateAdapter extends TemplateGenerator {
for (let col = 0; col < rows[0].length; col++) {
const column = {
- cn: rows[0][col]
+ cn: (rows[0][col] || `field${col + 1}`).replace(/\./, '_')
}
- const cellProps = ws[`${col.toString(26).split('').map(s => (parseInt(s, 26) + 10).toString(36).toUpperCase())}2`]
+ const cellProps = ws[`${col.toString(26).split('').map(s => (parseInt(s, 26) + 10).toString(36).toUpperCase())}2`] || {}
column.uidt = excelTypeToUidt[cellProps.t] || UITypes.SingleLineText
@@ -47,8 +51,8 @@ export default class ExcelTemplateAdapter extends TemplateGenerator {
const vals = rows.slice(1).map(r => r[col]).filter(v => v !== null && v !== undefined)
// check column is multi or single select by comparing unique values
- if (vals.some(v => v && v.includes(','))) {
- const flattenedVals = vals.flatMap(v => v ? v.split(',') : [])
+ if (vals.some(v => v && v.toString().includes(','))) {
+ const flattenedVals = vals.flatMap(v => v ? v.toString().split(',') : [])
const uniqueVals = new Set(flattenedVals)
if (flattenedVals.length > uniqueVals.size && uniqueVals.size <= flattenedVals.length / 10) {
column.uidt = UITypes.MultiSelect
diff --git a/packages/nc-gui/components/import/templateParsers/ExcelUrlTemplateAdapter.js b/packages/nc-gui/components/import/templateParsers/ExcelUrlTemplateAdapter.js
new file mode 100644
index 0000000000..dfbc9987d2
--- /dev/null
+++ b/packages/nc-gui/components/import/templateParsers/ExcelUrlTemplateAdapter.js
@@ -0,0 +1,20 @@
+import ExcelTemplateAdapter from '~/components/import/templateParsers/ExcelTemplateAdapter'
+
+export default class ExcelUrlTemplateAdapter extends ExcelTemplateAdapter {
+ constructor(url, $store) {
+ const name = url.split('/').pop()
+ super(name, null)
+ this.url = url
+ this.$store = $store
+ }
+
+ async init() {
+ const res = await this.$store.dispatch('sqlMgr/ActSqlOp', [null, 'handleAxiosCall',
+ [{
+ url: this.url,
+ responseType: 'arraybuffer'
+ }]])
+ this.excelData = res.data
+ await super.init()
+ }
+}
diff --git a/packages/nc-gui/components/import/TemplateGenerator.js b/packages/nc-gui/components/import/templateParsers/TemplateGenerator.js
similarity index 100%
rename from packages/nc-gui/components/import/TemplateGenerator.js
rename to packages/nc-gui/components/import/templateParsers/TemplateGenerator.js
diff --git a/packages/nc-gui/components/project/spreadsheet/components/csvExportImport.vue b/packages/nc-gui/components/project/spreadsheet/components/csvExportImport.vue
index 6ed84e518f..ce44d35dd7 100644
--- a/packages/nc-gui/components/project/spreadsheet/components/csvExportImport.vue
+++ b/packages/nc-gui/components/project/spreadsheet/components/csvExportImport.vue
@@ -74,8 +74,8 @@
import FileSaver from 'file-saver'
import DropOrSelectFileModal from '~/components/import/dropOrSelectFileModal'
-import CSVTemplateAdapter from '~/components/import/CSVTemplateAdapter'
import ColumnMappingModal from '~/components/project/spreadsheet/components/columnMappingModal'
+import CSVTemplateAdapter from '~/components/import/templateParsers/CSVTemplateAdapter'
export default {
name: 'CsvExportImport',
@@ -98,9 +98,9 @@ export default {
methods: {
async onCsvFileSelection(file) {
const reader = new FileReader()
-
- reader.onload = (e) => {
+ reader.onload = async(e) => {
const templateGenerator = new CSVTemplateAdapter(file.name, e.target.result)
+ await templateGenerator.init()
templateGenerator.parseData()
this.parsedCsv.columns = templateGenerator.getColumns()
this.parsedCsv.data = templateGenerator.getData()
diff --git a/packages/nc-gui/components/templates/createProjectFromTemplateBtn.vue b/packages/nc-gui/components/templates/createProjectFromTemplateBtn.vue
index 154cdf9b21..c47f6ca447 100644
--- a/packages/nc-gui/components/templates/createProjectFromTemplateBtn.vue
+++ b/packages/nc-gui/components/templates/createProjectFromTemplateBtn.vue
@@ -43,8 +43,8 @@ export default {
mixins: [colors],
props: {
loading: Boolean,
- templateData: Object,
- importData: Object,
+ templateData: [Array, Object],
+ importData: [Array, Object],
loaderMessage: String,
progress: Number
},
@@ -122,7 +122,10 @@ export default {
this.$ncApis.setProjectId(projectId)
let total = 0; let progress = 0
- await Promise.all(Object.entries(this.importData).map(async([table, data]) => {
+
+ console.log(this.importData)
+ debugger
+ await Promise.all(Object.entries(this.importData).map(v => (async([table, data]) => {
await this.$store.dispatch('meta/ActLoadMeta', {
tn: `${prefix}${table}`, project_id: projectId
})
@@ -142,7 +145,7 @@ export default {
}
this.$emit('update:progress', null)
- }))
+ })(v)))
}
}
diff --git a/packages/nc-gui/components/templates/editor.vue b/packages/nc-gui/components/templates/editor.vue
index f325dfef93..b199c36d14 100644
--- a/packages/nc-gui/components/templates/editor.vue
+++ b/packages/nc-gui/components/templates/editor.vue
@@ -571,7 +571,7 @@ export default {
props: {
id: [Number, String],
viewMode: Boolean,
- templateData: Object
+ projectTemplate: Object
},
data: () => ({
loading: false,
@@ -620,65 +620,68 @@ export default {
},
updateFilename() {
return this.url && this.url.split('/').pop()
- },
- projectTemplate() {
- const template = {
- ...this.project,
- tables: (this.project.tables || []).map((t) => {
- const table = { tn: t.tn, columns: [], hasMany: [], manyToMany: [], belongsTo: [], v: [] }
-
- for (const column of (t.columns || [])) {
- if (this.isRelation(column)) {
- if (column.type === 'hm') {
- table.hasMany.push({
- tn: column.rtn,
- _cn: column.cn
- })
- } else if (column.type === 'mm') {
- table.manyToMany.push({
- rtn: column.rtn,
- _cn: column.cn
- })
- } else if (column.uidt === UITypes.ForeignKey) {
- table.belongsTo.push({
- tn: column.rtn,
- _cn: column.cn
- })
- }
- } else if (this.isLookup(column)) {
- if (column.rtn) {
- table.v.push({
- _cn: column.cn,
- lk: {
- ltn: column.rtn.tn,
- type: column.rtn.type,
- lcn: column.rcn
- }
- })
- }
- } else if (this.isRollup(column)) {
- if (column.rtn) {
- table.v.push({
- _cn: column.cn,
- rl: {
- rltn: column.rtn.tn,
- rlcn: column.rcn,
- type: column.rtn.type,
- fn: column.fn
- }
- })
+ }
+ },
+ watch: {
+ project: {
+ deep: true,
+ handler() {
+ const template = {
+ ...this.project,
+ tables: (this.project.tables || []).map((t) => {
+ const table = { tn: t.tn, columns: [], hasMany: [], manyToMany: [], belongsTo: [], v: [] }
+
+ for (const column of (t.columns || [])) {
+ if (this.isRelation(column)) {
+ if (column.type === 'hm') {
+ table.hasMany.push({
+ tn: column.rtn,
+ _cn: column.cn
+ })
+ } else if (column.type === 'mm') {
+ table.manyToMany.push({
+ rtn: column.rtn,
+ _cn: column.cn
+ })
+ } else if (column.uidt === UITypes.ForeignKey) {
+ table.belongsTo.push({
+ tn: column.rtn,
+ _cn: column.cn
+ })
+ }
+ } else if (this.isLookup(column)) {
+ if (column.rtn) {
+ table.v.push({
+ _cn: column.cn,
+ lk: {
+ ltn: column.rtn.tn,
+ type: column.rtn.type,
+ lcn: column.rcn
+ }
+ })
+ }
+ } else if (this.isRollup(column)) {
+ if (column.rtn) {
+ table.v.push({
+ _cn: column.cn,
+ rl: {
+ rltn: column.rtn.tn,
+ rlcn: column.rcn,
+ type: column.rtn.type,
+ fn: column.fn
+ }
+ })
+ }
+ } else {
+ table.columns.push(column)
}
- } else {
- table.columns.push(column)
}
- }
- return table
- })
- }
-
- this.$emit('update:templateData', template)
+ return table
+ })
+ }
- return template
+ this.$emit('update:projectTemplate', template)
+ }
}
},
@@ -689,8 +692,8 @@ export default {
document.removeEventListener('keydown', this.handleKeyDown)
},
mounted() {
- if (this.templateData) {
- this.parseTemplate(this.templateData)
+ if (this.projectTemplate) {
+ this.parseTemplate(this.projectTemplate)
this.expansionPanel = Array.from({ length: this.project.tables.length }, (_, i) => i)
}
const input = this.$refs.projec && this.$refs.project.$el.querySelector('input')
diff --git a/packages/nc-gui/pages/projects/index.vue b/packages/nc-gui/pages/projects/index.vue
index cc8077cf22..e34aa607e3 100644
--- a/packages/nc-gui/pages/projects/index.vue
+++ b/packages/nc-gui/pages/projects/index.vue
@@ -210,7 +210,7 @@
"
/>
-
+ -->
- <!– Create By Connecting
To An External Database –>
- -->
+
@@ -262,7 +261,7 @@
'items-per-page-options': [20, -1],
}"
class="pa-4 text-left mx-auto "
- style="cursor: pointer"
+ style="cursor: pointer; max-width: 100%"
>
-
- mdi-moon-full
-
-
-
- {{
- props.item.projectType === 'graphql'
- ? 'mdi-graphql'
- : 'mdi-code-json'
- }}
-
+
+
+ mdi-moon-full
+
+
+
+ {{
+ props.item.projectType === 'graphql'
+ ? 'mdi-graphql'
+ : 'mdi-code-json'
+ }}
+
- {{
- props.item.title
- }}
+
+
+
+ {{
+ props.item.title
+ }}
+
+
+ {{ props.item.title }}
+
+
|
-
+ |
|