feature: add multi file upload in gcode-files & config-files

feature: add upload status in config-files

Signed-off-by: Stefan Dej <meteyou@gmail.com>
This commit is contained in:
Stefan Dej 2020-12-31 01:37:58 +01:00
parent 6856c9a99f
commit e44e3bc540
2 changed files with 143 additions and 45 deletions

View File

@ -30,7 +30,7 @@
<v-card-title> <v-card-title>
Config Files Config Files
<v-spacer class="d-none d-sm-block"></v-spacer> <v-spacer class="d-none d-sm-block"></v-spacer>
<input type="file" ref="fileUpload" style="display: none" @change="uploadFile" /> <input type="file" ref="fileUpload" style="display: none" multiple @change="uploadFile" />
<v-item-group class="v-btn-toggle my-5 my-sm-0 col-12 col-sm-auto px-0 py-0"> <v-item-group class="v-btn-toggle my-5 my-sm-0 col-12 col-sm-auto px-0 py-0">
<v-btn v-if="currentPath !== '' && currentPath !== '/config_examples'" class="flex-grow-1" @click="uploadFileButton" :loading="loadings.includes['configFileUpload']"><v-icon>mdi-file-upload</v-icon></v-btn> <v-btn v-if="currentPath !== '' && currentPath !== '/config_examples'" class="flex-grow-1" @click="uploadFileButton" :loading="loadings.includes['configFileUpload']"><v-icon>mdi-file-upload</v-icon></v-btn>
<v-btn v-if="currentPath !== '' && currentPath !== '/config_examples'" class="flex-grow-1" @click="createFile"><v-icon>mdi-file-plus</v-icon></v-btn> <v-btn v-if="currentPath !== '' && currentPath !== '/config_examples'" class="flex-grow-1" @click="createFile"><v-icon>mdi-file-plus</v-icon></v-btn>
@ -176,6 +176,30 @@
</v-card-actions> </v-card-actions>
</v-card> </v-card>
</v-dialog> </v-dialog>
<v-snackbar
:timeout="-1"
:value="true"
fixed
right
bottom
dark
v-model="uploadSnackbar.status"
>
<span v-if="uploadSnackbar.max > 1" class="mr-1">({{ uploadSnackbar.number }}/{{ uploadSnackbar.max }})</span><strong>Uploading {{ uploadSnackbar.filename }}</strong><br />
{{ Math.round(uploadSnackbar.percent) }} % @ {{ formatFilesize(Math.round(uploadSnackbar.speed)) }}/s<br />
<v-progress-linear class="mt-2" :value="uploadSnackbar.percent"></v-progress-linear>
<template v-slot:action="{ attrs }">
<v-btn
color="red"
text
v-bind="attrs"
@click="cancelUpload"
style="min-width: auto;"
>
<v-icon class="0">mdi-close</v-icon>
</v-btn>
</template>
</v-snackbar>
</div> </div>
</template> </template>
@ -243,6 +267,20 @@
show: false, show: false,
name: "", name: "",
}, },
uploadSnackbar: {
status: false,
filename: "",
percent: 0,
speed: 0,
total: 0,
number: 0,
max: 0,
cancelTokenSource: "",
lastProgress: {
time: 0,
loaded: 0
}
}
} }
}, },
computed: { computed: {
@ -461,30 +499,75 @@
uploadFileButton: function() { uploadFileButton: function() {
this.$refs.fileUpload.click() this.$refs.fileUpload.click()
}, },
uploadFile: function() { async uploadFile() {
if (this.$refs.fileUpload.files.length) { if (this.$refs.fileUpload.files.length) {
this.doUploadFile(this.$refs.fileUpload.files[0]).finally(() => { this.$store.commit('socket/addLoading', { name: 'configFileUpload' })
this.$refs.fileUpload.value = '' let successFiles = []
}) this.uploadSnackbar.number = 0
this.uploadSnackbar.max = this.$refs.fileUpload.files.length
for (const file of this.$refs.fileUpload.files) {
this.uploadSnackbar.number++
const result = await this.doUploadFile(file)
successFiles.push(result)
}
this.$store.commit('socket/removeLoading', { name: 'configFileUpload' })
for(const file of successFiles) {
this.$toast.success("Upload of "+file+" successful!")
}
this.$refs.fileUpload.value = ''
} }
}, },
doUploadFile: function(file) { doUploadFile: function(file) {
let toast = this.$toast; let toast = this.$toast;
let formData = new FormData(); let formData = new FormData();
let filename = file.name.replace(" ", "_"); let filename = file.name.replace(" ", "_");
this.uploadSnackbar.filename = filename
this.uploadSnackbar.status = true
this.uploadSnackbar.percent = 0
this.uploadSnackbar.speed = 0
this.uploadSnackbar.lastProgress.loaded = 0
this.uploadSnackbar.lastProgress.time = 0
formData.append('root', 'config'); formData.append('root', 'config');
formData.append('file', file, (this.currentPath+"/"+filename).substring(7)); formData.append('file', file, (this.currentPath+"/"+filename).substring(7));
this.$store.commit('socket/addLoading', { name: 'configFileUpload' }); this.$store.commit('socket/addLoading', { name: 'configFileUpload' });
return axios.post('//' + this.hostname + ':' + this.port + '/server/files/upload', return new Promise(resolve => {
formData, { headers: { 'Content-Type': 'multipart/form-data' } } this.uploadSnackbar.cancelTokenSource = axios.CancelToken.source();
).then((result) => { axios.post('//' + this.hostname + ':' + this.port + '/server/files/upload',
this.$store.commit('socket/removeLoading', { name: 'configFileUpload' }); formData, {
toast.success("Upload of "+result.data.result+" successful!"); headers: { 'Content-Type': 'multipart/form-data' },
}).catch(() => { cancelToken: this.uploadSnackbar.cancelTokenSource.token,
this.$store.commit('socket/removeLoading', { name: 'configFileUpload' }); onUploadProgress: (progressEvent) => {
toast.error("Cannot upload the file!"); this.uploadSnackbar.percent = (progressEvent.loaded * 100) / progressEvent.total
}); if (this.uploadSnackbar.lastProgress.time) {
const time = progressEvent.timeStamp - this.uploadSnackbar.lastProgress.time
const data = progressEvent.loaded - this.uploadSnackbar.lastProgress.loaded
if (time) this.uploadSnackbar.speed = data / (time / 1000)
}
this.uploadSnackbar.lastProgress.time = progressEvent.timeStamp
this.uploadSnackbar.lastProgress.loaded = progressEvent.loaded
this.uploadSnackbar.total = progressEvent.total
}
}
).then((result) => {
this.uploadSnackbar.status = false
resolve(result.data.result)
}).catch(() => {
this.uploadSnackbar.status = false
this.$store.commit('socket/removeLoading', { name: 'configFileUpload' });
toast.error("Cannot upload the file!");
})
})
},
cancelUpload: function() {
this.uploadSnackbar.cancelTokenSource.cancel()
this.uploadSnackbar.status = false
}, },
}, },
watch: { watch: {

View File

@ -53,7 +53,7 @@
<v-card-title> <v-card-title>
G-Code Files G-Code Files
<v-spacer class="d-none d-sm-block"></v-spacer> <v-spacer class="d-none d-sm-block"></v-spacer>
<input type="file" ref="fileUpload" accept=".gcode" style="display: none" @change="uploadFile" /> <input type="file" ref="fileUpload" accept=".gcode" style="display: none" multiple @change="uploadFile" />
<v-item-group class="v-btn-toggle my-5 my-sm-0 col-12 col-sm-auto px-0 py-0" name="controllers"> <v-item-group class="v-btn-toggle my-5 my-sm-0 col-12 col-sm-auto px-0 py-0" name="controllers">
<v-btn @click="clickUploadButton" title="Upload new Gcode" class="primary flex-grow-1" :loading="loadings.includes('gcodeUpload')"><v-icon>mdi-upload</v-icon></v-btn> <v-btn @click="clickUploadButton" title="Upload new Gcode" class="primary flex-grow-1" :loading="loadings.includes('gcodeUpload')"><v-icon>mdi-upload</v-icon></v-btn>
<v-btn @click="createDirectory" title="Create new Directory" class="flex-grow-1"><v-icon>mdi-folder-plus</v-icon></v-btn> <v-btn @click="createDirectory" title="Create new Directory" class="flex-grow-1"><v-icon>mdi-folder-plus</v-icon></v-btn>
@ -240,7 +240,7 @@
dark dark
v-model="uploadSnackbar.status" v-model="uploadSnackbar.status"
> >
<strong>Uploading {{ uploadSnackbar.filename }}</strong><br /> <span v-if="uploadSnackbar.max > 1" class="mr-1">({{ uploadSnackbar.number }}/{{ uploadSnackbar.max }})</span><strong>Uploading {{ uploadSnackbar.filename }}</strong><br />
{{ Math.round(uploadSnackbar.percent) }} % @ {{ formatFilesize(Math.round(uploadSnackbar.speed)) }}/s<br /> {{ Math.round(uploadSnackbar.percent) }} % @ {{ formatFilesize(Math.round(uploadSnackbar.speed)) }}/s<br />
<v-progress-linear class="mt-2" :value="uploadSnackbar.percent"></v-progress-linear> <v-progress-linear class="mt-2" :value="uploadSnackbar.percent"></v-progress-linear>
<template v-slot:action="{ attrs }"> <template v-slot:action="{ attrs }">
@ -329,6 +329,8 @@
percent: 0, percent: 0,
speed: 0, speed: 0,
total: 0, total: 0,
number: 0,
max: 0,
cancelTokenSource: "", cancelTokenSource: "",
lastProgress: { lastProgress: {
time: 0, time: 0,
@ -390,11 +392,24 @@
}) })
}, },
methods: { methods: {
uploadFile: function() { async uploadFile() {
if (this.$refs.fileUpload.files.length) { if (this.$refs.fileUpload.files.length) {
this.doUploadFile(this.$refs.fileUpload.files[0]).finally(() => { this.$store.commit('socket/addLoading', { name: 'gcodeUpload' })
this.$refs.fileUpload.value = '' let successFiles = []
}) this.uploadSnackbar.number = 0
this.uploadSnackbar.max = this.$refs.fileUpload.files.length
for (const file of this.$refs.fileUpload.files) {
this.uploadSnackbar.number++
const result = await this.doUploadFile(file)
successFiles.push(result)
}
this.$store.commit('socket/removeLoading', { name: 'gcodeUpload' })
for(const file of successFiles) {
this.$toast.success("Upload of "+file+" successful!")
}
this.$refs.fileUpload.value = ''
} }
}, },
doUploadFile: function(file) { doUploadFile: function(file) {
@ -410,35 +425,35 @@
this.uploadSnackbar.lastProgress.time = 0 this.uploadSnackbar.lastProgress.time = 0
formData.append('file', file, (this.currentPath+"/"+filename).substring(7)) formData.append('file', file, (this.currentPath+"/"+filename).substring(7))
this.$store.commit('socket/addLoading', { name: 'gcodeUpload' })
this.uploadSnackbar.cancelTokenSource = axios.CancelToken.source(); return new Promise(resolve => {
return axios.post('//' + this.hostname + ':' + this.port + '/server/files/upload', this.uploadSnackbar.cancelTokenSource = axios.CancelToken.source();
formData, { axios.post('//' + this.hostname + ':' + this.port + '/server/files/upload',
cancelToken: this.uploadSnackbar.cancelTokenSource.token, formData, {
headers: { 'Content-Type': 'multipart/form-data' }, cancelToken: this.uploadSnackbar.cancelTokenSource.token,
onUploadProgress: (progressEvent) => { headers: { 'Content-Type': 'multipart/form-data' },
this.uploadSnackbar.percent = (progressEvent.loaded * 100) / progressEvent.total onUploadProgress: (progressEvent) => {
if (this.uploadSnackbar.lastProgress.time) { this.uploadSnackbar.percent = (progressEvent.loaded * 100) / progressEvent.total
const time = progressEvent.timeStamp - this.uploadSnackbar.lastProgress.time if (this.uploadSnackbar.lastProgress.time) {
const data = progressEvent.loaded - this.uploadSnackbar.lastProgress.loaded const time = progressEvent.timeStamp - this.uploadSnackbar.lastProgress.time
const data = progressEvent.loaded - this.uploadSnackbar.lastProgress.loaded
if (time) this.uploadSnackbar.speed = data / (time / 1000) if (time) this.uploadSnackbar.speed = data / (time / 1000)
}
this.uploadSnackbar.lastProgress.time = progressEvent.timeStamp
this.uploadSnackbar.lastProgress.loaded = progressEvent.loaded
this.uploadSnackbar.total = progressEvent.total
} }
this.uploadSnackbar.lastProgress.time = progressEvent.timeStamp
this.uploadSnackbar.lastProgress.loaded = progressEvent.loaded
this.uploadSnackbar.total = progressEvent.total
} }
} ).then((result) => {
).then((result) => { this.uploadSnackbar.status = false
this.uploadSnackbar.status = false resolve(result.data.result)
this.$store.commit('socket/removeLoading', { name: 'gcodeUpload' }) }).catch(() => {
toast.success("Upload of "+result.data.result+" successful!") this.uploadSnackbar.status = false
}).catch(() => { this.$store.commit('socket/removeLoading', { name: 'gcodeUpload' })
this.uploadSnackbar.status = false toast.error("Cannot upload the file!")
this.$store.commit('socket/removeLoading', { name: 'gcodeUpload' }) })
toast.error("Cannot upload the file!")
}) })
}, },
clickUploadButton: function() { clickUploadButton: function() {