vikunja/src/components/tasks/reusable/attachments.vue
konrad 4e42810522 Update tasks in kanban board after editing them in task detail view (#130)
Fix due date disappearing after moving it

Fix removing labels not being updated in store

Fix adding labels not being updated in store

Fix removing assignees not being updated in store

Fix adding assignees not being updated in store

Fix due date not resetting

Fix task attachments not updating in store after being modified in popup view

Fix due date not updating in store after being modified in popup view

Fix using filters for overview views

Fix not re-loading tasks when switching between overviews

Only show undone tasks on task overview page

Update task in bucket when updating in task detail view

Put all bucket related stuff in store

Co-authored-by: kolaente <k@knt.li>
Reviewed-on: vikunja/frontend#130
2020-05-09 17:00:54 +00:00

198 lines
4.9 KiB
Vue

<template>
<div class="attachments">
<h3>
<span class="icon is-grey">
<icon icon="paperclip"/>
</span>
Attachments
<a
class="button is-primary is-outlined is-small noshadow"
@click="$refs.files.click()"
:disabled="attachmentService.loading">
<span class="icon is-small"><icon icon="cloud-upload-alt"/></span>
Upload attachment
</a>
</h3>
<input type="file" id="files" ref="files" multiple @change="uploadNewAttachment()" :disabled="attachmentService.loading"/>
<progress v-if="attachmentService.uploadProgress > 0" class="progress is-primary" :value="attachmentService.uploadProgress" max="100">{{ attachmentService.uploadProgress }}%</progress>
<table>
<tr>
<th>Name</th>
<th>Size</th>
<th>Type</th>
<th>Date</th>
<th>Created By</th>
<th>Action</th>
</tr>
<tr class="attachment" v-for="a in attachments" :key="a.id">
<td>
{{ a.file.name }}
</td>
<td>{{ a.file.getHumanSize() }}</td>
<td>{{ a.file.mime }}</td>
<td v-tooltip="formatDate(a.created)">{{ formatDateSince(a.created) }}</td>
<td><user :user="a.createdBy" :avatar-size="30"/></td>
<td>
<div class="buttons has-addons">
<a class="button is-primary noshadow" @click="downloadAttachment(a)" v-tooltip="'Download this attachment'">
<span class="icon">
<icon icon="cloud-download-alt"/>
</span>
</a>
<a class="button is-danger noshadow" v-tooltip="'Delete this attachment'" @click="() => {attachmentToDelete = a; showDeleteModal = true}">
<span class="icon">
<icon icon="trash-alt"/>
</span>
</a>
</div>
</td>
</tr>
</table>
<!-- Dropzone -->
<div class="dropzone" :class="{ 'hidden': !showDropzone }">
<div class="drop-hint">
<div class="icon">
<icon icon="cloud-upload-alt"/>
</div>
<div class="hint">
Drop files here to upload
</div>
</div>
</div>
<!-- Delete modal -->
<modal
v-if="showDeleteModal"
@close="showDeleteModal = false"
v-on:submit="deleteAttachment()">
<span slot="header">Delete attachment</span>
<p slot="text">Are you sure you want to delete the attachment {{ attachmentToDelete.file.name }}?<br/>
<b>This CANNOT BE UNDONE!</b></p>
</modal>
</div>
</template>
<script>
import AttachmentService from '../../../services/attachment'
import AttachmentModel from '../../../models/attachment'
import User from '../../global/user'
export default {
name: 'attachments',
components: {
User,
},
data() {
return {
attachments: [],
attachmentService: AttachmentService,
showDropzone: false,
showDeleteModal: false,
attachmentToDelete: AttachmentModel,
}
},
props: {
taskId: {
required: true,
type: Number,
},
initialAttachments: {
type: Array,
}
},
created() {
this.attachmentService = new AttachmentService()
this.attachments = this.initialAttachments
},
mounted() {
document.addEventListener('dragenter', e => {
e.stopPropagation()
e.preventDefault()
this.showDropzone = true
});
window.addEventListener('dragleave', e => {
e.stopPropagation()
e.preventDefault()
this.showDropzone = false
});
document.addEventListener('dragover', e => {
e.stopPropagation()
e.preventDefault()
this.showDropzone = true
});
document.addEventListener('drop', e => {
e.stopPropagation()
e.preventDefault()
let files = e.dataTransfer.files
this.uploadFiles(files)
this.showDropzone = false
})
},
watch: {
initialAttachments(newVal) {
this.attachments = newVal
},
},
methods: {
downloadAttachment(attachment) {
this.attachmentService.download(attachment)
},
uploadNewAttachment() {
if(this.$refs.files.files.length === 0) {
return
}
this.uploadFiles(this.$refs.files.files)
},
uploadFiles(files) {
const attachmentModel = new AttachmentModel({taskId: this.taskId})
this.attachmentService.create(attachmentModel, files)
.then(r => {
if(r.success !== null) {
r.success.forEach(a => {
this.success({message: 'Successfully uploaded ' + a.file.name}, this)
this.attachments.push(a)
this.$store.dispatch('tasks/addTaskAttachment', {taskId: this.taskId, attachment: a})
})
}
if(r.errors !== null) {
r.errors.forEach(m => {
this.error(m)
})
}
})
.catch(e => {
this.error(e, this)
})
},
deleteAttachment() {
this.attachmentService.delete(this.attachmentToDelete)
.then(r => {
// Remove the file from the list
for (const a in this.attachments) {
if (this.attachments[a].id === this.attachmentToDelete.id) {
this.attachments.splice(a, 1)
}
}
this.success(r, this)
})
.catch(e => {
this.error(e, this)
})
.finally(() => {
this.showDeleteModal = false
})
},
},
}
</script>