Commit fcab0502 by Jonathan Thomas

Added file upload progress to the UI. Multiple upload progress bars are…

Added file upload progress to the UI. Multiple upload progress bars are supported. Also, clicking on a file now previews the selected file. Video and images are supported.
parent 73135ab9
......@@ -7,15 +7,24 @@
<label for="floatingInput">Search</label>
</div>
</div>
<div v-for="file in files" :key="file.id" class="col-4" style="overflow: scroll;">
<div v-for="file in files" :key="file.id" class="col-4">
<img @click="toggleSelection(file)" :class="getSelectedClass(file)" class="file-thumbnail img-fluid img-thumbnail" :title="file.name" src="../assets/logo.png"/>
</div>
<div v-for="upload in uploads" :key="upload.id" class="col-4">
<div class="row h-100">
<div class="col-sm-12 my-auto p-3">
<div class="progress align-middle">
<div class="progress-bar" role="progressbar" v-bind:style="{ width: upload.progress + '%'}" :aria-valuenow="upload.progress" aria-valuemin="0" aria-valuemax="100"></div>
</div>
</div>
</div>
</div>
<input ref="fileUpload" type="file" @change="fileChanged" hidden>
</div>
</template>
<script>
import { mapActions, mapState } from "vuex";
import { mapActions, mapState, mapMutations } from "vuex";
export default {
name: "Files.vue",
......@@ -27,7 +36,7 @@ export default {
chooseFiles() {
this.$refs.fileUpload.click()
},
fileChanged(event) {
async fileChanged(event) {
let data = new FormData();
data.append('media', event.target.files[0]);
data.append('project', this.project.url);
......@@ -35,23 +44,25 @@ export default {
let payload = { project_id: this.project.id,
project_url: this.project.url,
data}
this.createFile(payload)
await this.createFile(payload)
this.$refs.fileUpload.value = null
},
toggleSelection(fileObject) {
fileObject.selected = !fileObject.selected
this.setPreviewFile(fileObject)
},
getSelectedClass(fileObject) {
if (fileObject.selected) {
if (this.previewFile && fileObject.id == this.previewFile.id) {
return 'selected'
} else {
return ''
}
},
...mapActions(['loadFiles', 'createFile'])
...mapActions(['loadFiles', 'createFile']),
...mapMutations((['setPreviewFile']))
},
computed: {
...mapState(['files'])
...mapState(['files', 'previewFile', 'uploads'])
},
mounted() {
this.loadFiles(this.project.id)
......
<template>
<h3 class="p-2">Preview <button type="button" class="btn btn-danger export-btn">Export</button></h3>
<video controls="" preload="" poster="http://sandbox.thewikies.com/vfe-generator/images/big-buck-bunny_poster.jpg" class="video-responsive" id="video1" width="100%" height="100%">
<source type="video/mp4" src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4">
<source type="video/webm" src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.webm">
<source type="video/ogg" src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.ogv">
<track src="Content/audio/captions.vtt" kind="subtitles" srclang="en" label="English">
<img alt="Big Buck Bunny" src="http://sandbox.thewikies.com/vfe-generator/images/big-buck-bunny_poster.jpg" width="640" height="360" title="No video playback capabilities, please download the video below">
<video v-if="!isImage && hasPreviewFile" controls="" preload="" poster="" class="video-responsive">
<source :type="previewFormat" :src="previewFile.media">
</video>
<img v-if="isImage && hasPreviewFile" :src="previewFile.media" class="img-fluid img-thumbnail" />
</template>
<script>
import {mapState} from "vuex";
export default {
name: "Preview.vue",
props: ['project']
props: ['project'],
methods: {
},
computed: {
...mapState(['previewFile']),
hasPreviewFile() {
if (this.previewFile) {
return true
} else {
return false
}
},
isImage() {
return (this.previewFile && this.previewFile.json.vcodec == "QImage")
},
previewFormat() {
if (this.previewFile) {
return `video/${this.previewFile.media.split('.').pop()}`
}
return ''
}
}
}
</script>
......
......@@ -5,11 +5,12 @@ import { instance } from "./axios"
export default createStore({
state: {
counter: 1,
projects: [],
files: [],
user: null,
errors: []
errors: [],
previewFile: null,
uploads: []
},
mutations: {
......@@ -31,7 +32,24 @@ export default createStore({
},
setFiles(state, files) {
state.files = files
},
setPreviewFile(state, file) {
state.previewFile = file
},
addUpload(state, upload) {
state.uploads.push(upload)
},
updateUpload(state, upload) {
for (const up of state.uploads) {
if (up.id == upload.id) {
up.progress = upload.progress
break
}
}
},
removeUpload(state, uploadID) {
state.uploads = state.uploads.filter(up => up.id != uploadID )
},
},
getters: {
isAuthenticated: state => !!state.user
......@@ -88,10 +106,24 @@ export default createStore({
}
},
async createFile({dispatch, commit}, payload) {
let uploadID = uuidv4()
let uploadObject = { 'id': uploadID, progress: 0 }
commit('addUpload', uploadObject)
const config = {
onUploadProgress: progressEvent => {
let progress = (progressEvent.loaded / progressEvent.total) * 100;
let uploadObject = { 'id': uploadID, progress }
commit('updateUpload', uploadObject)
}
}
try {
await instance.post(`${payload.project_url}files/`, payload.data)
await instance.post(`${payload.project_url}files/`, payload.data, config)
commit('removeUpload', uploadID)
dispatch('loadFiles', payload.project_id)
} catch(err) {
commit('removeUpload', uploadID)
commit('addError', JSON.stringify(err.response.data))
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment