Browse Source

feat: add proper progressbar for excel import

Signed-off-by: Pranav C <pranavxc@gmail.com>
pull/765/head
Pranav C 3 years ago
parent
commit
dad9e39f54
  1. 44
      packages/nc-gui/components/import/excelImport.vue
  2. 20
      packages/nc-gui/components/templates/createProjectFromTemplateBtn.vue
  3. 4
      packages/nc-gui/store/meta.js
  4. 1
      packages/nc-gui/store/sqlMgr.js
  5. 2
      packages/nocodb/src/example/try.ts
  6. 10
      packages/nocodb/src/lib/noco/NcProjectBuilder.ts
  7. 2
      packages/nocodb/src/lib/noco/meta/NcMetaIO.ts
  8. 4
      packages/nocodb/src/lib/noco/meta/NcMetaIOImpl.ts

44
packages/nc-gui/components/import/excelImport.vue

@ -26,7 +26,14 @@
<v-tooltip bottom> <v-tooltip bottom>
<template #activator="{on}"> <template #activator="{on}">
<input ref="file" type="file" style="display: none" accept=".xlsx, .xls" @change="_change($event)"> <input
ref="file"
class="nc-excel-import-input"
type="file"
style="display: none"
accept=".xlsx, .xls"
@change="_change($event)"
>
<v-btn <v-btn
v-if="!hideLabel" v-if="!hideLabel"
@ -51,6 +58,7 @@
<v-spacer /> <v-spacer />
<create-project-from-template-btn <create-project-from-template-btn
:loader-message.sync="loaderMessage" :loader-message.sync="loaderMessage"
:progress.sync="progress"
:template-data="templateData" :template-data="templateData"
:import-data="importData" :import-data="importData"
/> />
@ -61,7 +69,17 @@
<v-overlay :value="loaderMessage" z-index="99999" opacity=".9"> <v-overlay :value="loaderMessage" z-index="99999" opacity=".9">
<div class="d-flex flex-column align-center"> <div class="d-flex flex-column align-center">
<v-progress-circular indeterminate size="100" width="15" class="mb-10" /> <v-progress-circular
v-if="progress !== null "
:rotate="360"
:size="100"
:width="15"
:value="progress"
>
{{ progress }}%
</v-progress-circular>
<v-progress-circular v-else indeterminate size="100" width="15" class="mb-10" />
<span class="title">{{ loaderMessage }}</span> <span class="title">{{ loaderMessage }}</span>
</div> </div>
</v-overlay> </v-overlay>
@ -87,7 +105,8 @@ export default {
templateData: null, templateData: null,
importData: null, importData: null,
dragOver: false, dragOver: false,
loaderMessage: null loaderMessage: null,
progress: null
} }
}, },
computed: { computed: {
@ -115,20 +134,31 @@ export default {
this._file(files[0]) this._file(files[0])
} }
}, },
_file(file) { async _file(file) {
this.loaderMessage = 'Loading excel file...' this.loaderMessage = 'Loading excel file'
let i = 0
const int = setInterval(() => {
this.loaderMessage = `Loading excel file${'.'.repeat(++i % 4)}`
}, 1000)
this.dropOrUpload = false this.dropOrUpload = false
console.time('excelImport')
const reader = new FileReader() const reader = new FileReader()
reader.onload = (e) => { reader.onload = (e) => {
const ab = e.target.result const ab = e.target.result
const templateGenerator = new ExcelTemplateAdapter(file.name, ab) const templateGenerator = new ExcelTemplateAdapter(file.name, ab)
templateGenerator.parse() templateGenerator.parse()
this.templateData = templateGenerator.getTemplate() this.templateData = templateGenerator.getTemplate()
this.importData = templateGenerator.getData() this.importData = templateGenerator.getData()
console.timeEnd('excelImport')
this.loaderMessage = null this.loaderMessage = null
clearInterval(int)
}
const handleEvent = (event) => {
this.loaderMessage = `${event.type}: ${event.loaded} bytes transferred`
} }
reader.addEventListener('progress', handleEvent)
reader.onerror = () => { reader.onerror = () => {
this.loaderMessage = null this.loaderMessage = null
} }

20
packages/nc-gui/components/templates/createProjectFromTemplateBtn.vue

@ -45,7 +45,8 @@ export default {
loading: Boolean, loading: Boolean,
templateData: Object, templateData: Object,
importData: Object, importData: Object,
loaderMessage: String loaderMessage: String,
progress: Number
}, },
data() { data() {
return { return {
@ -82,7 +83,6 @@ export default {
this.projectCreation = true this.projectCreation = true
try { try {
const interv = setInterval(() => { const interv = setInterval(() => {
debugger
this.loaderMessagesIndex = this.loaderMessagesIndex < this.loaderMessages.length - 1 ? this.loaderMessagesIndex + 1 : 6 this.loaderMessagesIndex = this.loaderMessagesIndex < this.loaderMessages.length - 1 ? this.loaderMessagesIndex + 1 : 6
this.$emit('update:loaderMessage', this.loaderMessages[this.loaderMessagesIndex]) this.$emit('update:loaderMessage', this.loaderMessages[this.loaderMessagesIndex])
}, 1000) }, 1000)
@ -118,12 +118,13 @@ export default {
this.projectCreation = false this.projectCreation = false
}, },
async importDataToProject({ projectId, projectType, prefix = '' }) { async importDataToProject({ projectId, projectType, prefix = '' }) {
this.$store.commit('project/MutProjectId', projectId) // this.$store.commit('project/MutProjectId', projectId)
this.$ncApis.setProjectId(projectId) this.$ncApis.setProjectId(projectId)
let total = 0; let progress = 0
await Promise.all(Object.entries(this.importData).map(async([table, data]) => { await Promise.all(Object.entries(this.importData).map(async([table, data]) => {
await this.$store.dispatch('meta/ActLoadMeta', { await this.$store.dispatch('meta/ActLoadMeta', {
tn: `${prefix}${table}` tn: `${prefix}${table}`, project_id: projectId
}) })
// todo: get table name properly // todo: get table name properly
@ -131,11 +132,16 @@ export default {
table: `${prefix}${table}`, table: `${prefix}${table}`,
type: projectType type: projectType
}) })
total += data.length
for (let i = 0; i < data.length; i += 500) { for (let i = 0; i < data.length; i += 500) {
console.log(data[i]) this.$emit('update:loaderMessage', `Importing data : ${progress}/${total}`)
await api.insertBulk(data.slice(i, i + 500)) this.$emit('update:progress', Math.round(progress && 100 * progress / total))
const batchData = data.slice(i, i + 500)
await api.insertBulk(batchData)
progress += batchData.length
} }
this.$emit('update:progress', null)
})) }))
} }
} }

4
packages/nc-gui/store/meta.js

@ -16,7 +16,7 @@ export const mutations = {
} }
export const actions = { export const actions = {
async ActLoadMeta({ state, commit, dispatch }, { tn, env = '_noco', dbAlias = 'db', force }) { async ActLoadMeta({ state, commit, dispatch }, { tn, env = '_noco', dbAlias = 'db', force, project_id }) {
if (!force && state.loading[tn]) { if (!force && state.loading[tn]) {
return await new Promise((resolve) => { return await new Promise((resolve) => {
const unsubscribe = this.app.store.subscribe((s) => { const unsubscribe = this.app.store.subscribe((s) => {
@ -34,7 +34,7 @@ export const actions = {
key: tn, key: tn,
value: true value: true
}) })
const model = await dispatch('sqlMgr/ActSqlOp', [{ env, dbAlias }, 'tableXcModelGet', { tn }], { root: true }) const model = await dispatch('sqlMgr/ActSqlOp', [{ env, dbAlias, project_id }, 'tableXcModelGet', { tn }], { root: true })
const meta = JSON.parse(model.meta) const meta = JSON.parse(model.meta)
commit('MutMeta', { commit('MutMeta', {
key: tn, key: tn,

1
packages/nc-gui/store/sqlMgr.js

@ -361,7 +361,6 @@ export const actions = {
dispatch dispatch
}, [args, op, opArgs, cusHeaders, cusAxiosOptions, queryParams, returnResponse]) { }, [args, op, opArgs, cusHeaders, cusAxiosOptions, queryParams, returnResponse]) {
const params = {} const params = {}
params.project_id = rootState.project.projectId
if (this.$router.currentRoute && this.$router.currentRoute.params) { if (this.$router.currentRoute && this.$router.currentRoute.params) {
if (this.$router.currentRoute.params.project_id) { if (this.$router.currentRoute.params.project_id) {

2
packages/nocodb/src/example/try.ts

@ -24,7 +24,7 @@ process.env.NC_DB = url;
config, config,
'' ''
); );
await app.ncMeta.projectStatusUpdate(config.title, 'started'); await app.ncMeta.projectStatusUpdate(project.id, 'started');
await app.ncMeta.projectAddUser(project.id, 1, 'owner,creator'); await app.ncMeta.projectAddUser(project.id, 1, 'owner,creator');
} }
} }

10
packages/nocodb/src/lib/noco/NcProjectBuilder.ts

@ -48,7 +48,7 @@ export default class NcProjectBuilder {
this.startTime = Date.now(); this.startTime = Date.now();
const allRoutesInfo: any[] = []; const allRoutesInfo: any[] = [];
await this.app.ncMeta.projectStatusUpdate(this.title, 'starting'); await this.app.ncMeta.projectStatusUpdate(this.id, 'starting');
await this.syncMigration(); await this.syncMigration();
await this._createApiBuilder(); await this._createApiBuilder();
this.initApiInfoRoute(); this.initApiInfoRoute();
@ -72,10 +72,10 @@ export default class NcProjectBuilder {
} }
this.app.projectRouter.use(`/nc/${this.id}`, this.router); this.app.projectRouter.use(`/nc/${this.id}`, this.router);
await this.app.ncMeta.projectStatusUpdate(this.title, 'started'); await this.app.ncMeta.projectStatusUpdate(this.id, 'started');
} catch (e) { } catch (e) {
console.log(e); console.log(e);
await this.app.ncMeta.projectStatusUpdate(this.title, 'stopped'); await this.app.ncMeta.projectStatusUpdate(this.id, 'stopped');
} }
} }
@ -458,7 +458,7 @@ export default class NcProjectBuilder {
case 'projectStop': case 'projectStop':
this.router.stack.splice(0, this.router.stack.length); this.router.stack.splice(0, this.router.stack.length);
this.apiBuilders.splice(0, this.apiBuilders.length); this.apiBuilders.splice(0, this.apiBuilders.length);
await this.app.ncMeta.projectStatusUpdate(this.title, 'stopped'); await this.app.ncMeta.projectStatusUpdate(this.id, 'stopped');
NcProjectBuilder.triggerGarbageCollect(); NcProjectBuilder.triggerGarbageCollect();
this.app.ncMeta.audit(this.id, null, 'nc_audit', { this.app.ncMeta.audit(this.id, null, 'nc_audit', {
op_type: 'PROJECT', op_type: 'PROJECT',
@ -862,7 +862,7 @@ export default class NcProjectBuilder {
public async reInit() { public async reInit() {
this.router.stack.splice(0, this.router.stack.length); this.router.stack.splice(0, this.router.stack.length);
this.apiBuilders.splice(0, this.apiBuilders.length); this.apiBuilders.splice(0, this.apiBuilders.length);
await this.app.ncMeta.projectStatusUpdate(this.title, 'stopped'); await this.app.ncMeta.projectStatusUpdate(this.id, 'stopped');
const dbs = this.config?.envs?.[this.appConfig.workingEnv]?.db; const dbs = this.config?.envs?.[this.appConfig.workingEnv]?.db;
if (!dbs || !dbs.length) { if (!dbs || !dbs.length) {

2
packages/nocodb/src/lib/noco/meta/NcMetaIO.ts

@ -173,7 +173,7 @@ export default abstract class NcMetaIO {
): Promise<any>; ): Promise<any>;
public abstract projectStatusUpdate( public abstract projectStatusUpdate(
projectName: string, projectId: string,
status: string status: string
): Promise<any>; ): Promise<any>;

4
packages/nocodb/src/lib/noco/meta/NcMetaIOImpl.ts

@ -507,7 +507,7 @@ export default class NcMetaIOImpl extends NcMetaIO {
} }
public async projectStatusUpdate( public async projectStatusUpdate(
projectName: string, projectId: string,
status: string status: string
): Promise<any> { ): Promise<any> {
return this.knexConnection('nc_projects') return this.knexConnection('nc_projects')
@ -515,7 +515,7 @@ export default class NcMetaIOImpl extends NcMetaIO {
status status
}) })
.where({ .where({
title: projectName id: projectId
}); });
} }

Loading…
Cancel
Save