mirror of
https://gitlab.com/bramw/baserow.git
synced 2024-11-24 16:36:46 +00:00
237 lines
6.8 KiB
Vue
237 lines
6.8 KiB
Vue
<template>
|
|
<div class="control__elements">
|
|
<ul class="field-file__list">
|
|
<li
|
|
v-for="(file, index) in files"
|
|
:key="file.name + '-' + index"
|
|
class="field-file__item"
|
|
>
|
|
<FileInProgress
|
|
v-if="file.state === 'loading'"
|
|
:file="file"
|
|
:read-only="readOnly"
|
|
:icon-class="getIconClass(file.mime_type)"
|
|
@delete="forceRemoveFile(getFileInProgressIndex(file.id))"
|
|
/>
|
|
<FileFailed
|
|
v-else-if="file.state === 'failed'"
|
|
:file="file"
|
|
:read-only="readOnly"
|
|
:icon-class="getIconClass(file.mime_type)"
|
|
@delete="forceRemoveFile(getFileInProgressIndex(file.id))"
|
|
/>
|
|
<FileUploaded
|
|
v-else
|
|
:ref="`file-uploaded-${index}`"
|
|
:file="file"
|
|
:read-only="readOnly"
|
|
:icon-class="getIconClass(file.mime_type)"
|
|
@delete="removeFile(value, index)"
|
|
@rename="(name) => renameFile(value, index, name)"
|
|
@click="$refs.fileModal.show(index)"
|
|
/>
|
|
</li>
|
|
</ul>
|
|
<UploadFileDropzone v-if="!readOnly" @input="filesAdded($event)" />
|
|
<ButtonText
|
|
v-if="!readOnly"
|
|
icon="iconoir-plus"
|
|
@click.prevent="showModal()"
|
|
>
|
|
{{ $t('rowEditFieldFile.addFile') }}
|
|
</ButtonText>
|
|
<UserFilesModal
|
|
v-if="!readOnly"
|
|
ref="uploadModal"
|
|
:upload-file="uploadFile"
|
|
:user-file-upload-types="userFileUploadTypes"
|
|
@uploaded="addFiles(value, $event)"
|
|
></UserFilesModal>
|
|
<div v-show="touched && !valid" class="error">
|
|
{{ error }}
|
|
</div>
|
|
<FileFieldModal
|
|
v-if="Boolean(value)"
|
|
ref="fileModal"
|
|
:files="value"
|
|
:read-only="readOnly"
|
|
@removed="removeFile(value, $event)"
|
|
@renamed="renameFile(value, $event.index, $event.value)"
|
|
></FileFieldModal>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import { uuid } from '@baserow/modules/core/utils/string'
|
|
import FileFieldModal from '@baserow/modules/database/components/field/FileFieldModal'
|
|
import rowEditField from '@baserow/modules/database/mixins/rowEditField'
|
|
import fileField from '@baserow/modules/database/mixins/fileField'
|
|
import UploadFileDropzone from '@baserow/modules/core/components/files/UploadFileDropzone'
|
|
import UserFileService from '@baserow/modules/core/services/userFile'
|
|
import { UploadFileUserFileUploadType } from '@baserow/modules/core/userFileUploadTypes'
|
|
import UserFilesModal from '@baserow/modules/core/components/files/UserFilesModal'
|
|
import axios from 'axios'
|
|
import FileInProgress from '@baserow/modules/core/components/files/FileInProgress'
|
|
import FileFailed from '@baserow/modules/core/components/files/FileFailed'
|
|
import FileUploaded from '@baserow/modules/core/components/files/FileUploaded'
|
|
import { IMAGE_FILE_TYPES } from '@baserow/modules/core/enums'
|
|
|
|
export default {
|
|
components: {
|
|
FileUploaded,
|
|
FileFailed,
|
|
FileInProgress,
|
|
UploadFileDropzone,
|
|
FileFieldModal,
|
|
UserFilesModal,
|
|
},
|
|
mixins: [rowEditField, fileField],
|
|
props: {
|
|
uploadFile: {
|
|
type: Function,
|
|
required: false,
|
|
default: null,
|
|
},
|
|
userFileUploadTypes: {
|
|
type: Array,
|
|
required: false,
|
|
default: null,
|
|
},
|
|
},
|
|
data() {
|
|
return {
|
|
filesInProgress: [],
|
|
currentFileUploading: null,
|
|
cancelToken: null,
|
|
}
|
|
},
|
|
computed: {
|
|
files() {
|
|
return this.value?.concat(this.filesInProgress)
|
|
},
|
|
uploadFileFunction() {
|
|
return this.uploadFile || UserFileService(this.$client).uploadFile
|
|
},
|
|
},
|
|
methods: {
|
|
showModal() {
|
|
this.$refs.uploadModal.show(UploadFileUserFileUploadType.getType())
|
|
},
|
|
async filesAdded(event) {
|
|
const files = event.target.files || event.dataTransfer?.files
|
|
|
|
if (!files) {
|
|
return
|
|
}
|
|
|
|
let successfulUploads = []
|
|
const filesWithData = Array.from(files).map((file) => ({
|
|
file,
|
|
fileData: this.forceAddFile(file, { state: 'loading' }),
|
|
}))
|
|
|
|
for (const { file, fileData } of filesWithData) {
|
|
// File has been removed in the meantime
|
|
if (this.getFileInProgressIndex(fileData.id) === -1) {
|
|
continue
|
|
}
|
|
|
|
const progress = (event) => {
|
|
fileData.percentage = Math.round((event.loaded * 100) / event.total)
|
|
}
|
|
|
|
try {
|
|
this.currentFileUploading = fileData
|
|
this.cancelToken = axios.CancelToken.source()
|
|
const { data } = await this.uploadFileFunction(
|
|
file,
|
|
progress,
|
|
this.cancelToken.token
|
|
)
|
|
successfulUploads.push({
|
|
id: fileData.id,
|
|
order: this.getFileInProgressIndex(fileData.id),
|
|
data,
|
|
})
|
|
} catch (error) {
|
|
const message = error.handler.getMessage('userFile')
|
|
error.handler.handled()
|
|
this.forceUpdateFile(fileData.id, {
|
|
state: 'failed',
|
|
error: message.message,
|
|
})
|
|
}
|
|
}
|
|
|
|
// Make sure a file has not been removed after it has been uploaded
|
|
successfulUploads = successfulUploads.filter(
|
|
({ id }) => this.getFileInProgressIndex(id) !== -1
|
|
)
|
|
|
|
// Make sure to re-establish the order in which the files have been submitted
|
|
successfulUploads.sort((a, b) => a.order - b.order)
|
|
|
|
successfulUploads.forEach(({ id }) =>
|
|
this.forceRemoveFile(this.getFileInProgressIndex(id))
|
|
)
|
|
this.addFiles(
|
|
this.value,
|
|
successfulUploads.map(({ data }) => data)
|
|
)
|
|
},
|
|
forceUpdateFile(id, values) {
|
|
const fileIndex = this.getFileInProgressIndex(id)
|
|
this.$set(this.filesInProgress, fileIndex, {
|
|
...this.files[fileIndex],
|
|
...values,
|
|
})
|
|
},
|
|
forceRemoveFile(index) {
|
|
if (this.getFileInProgressIndex(this.currentFileUploading.id) === index) {
|
|
this.cancelToken.cancel()
|
|
}
|
|
this.filesInProgress.splice(index, 1)
|
|
},
|
|
forceAddFile(file, additionalData = {}) {
|
|
const id = uuid()
|
|
const fileData = {
|
|
id,
|
|
visible_name: file.name,
|
|
isImage: IMAGE_FILE_TYPES.includes(file.type),
|
|
percentage: 0,
|
|
...additionalData,
|
|
}
|
|
|
|
this.filesInProgress.push(fileData)
|
|
|
|
return fileData
|
|
},
|
|
removeFile(...args) {
|
|
fileField.methods.removeFile.call(this, ...args)
|
|
this.touch()
|
|
},
|
|
addFiles(...args) {
|
|
fileField.methods.addFiles.call(this, ...args)
|
|
this.touch()
|
|
},
|
|
renameFile(value, index, newName) {
|
|
const success = fileField.methods.renameFile.call(
|
|
this,
|
|
value,
|
|
index,
|
|
newName
|
|
)
|
|
|
|
if (!success) {
|
|
this.$refs[`file-uploaded-${index}`][0].resetName()
|
|
}
|
|
|
|
this.touch()
|
|
},
|
|
getFileInProgressIndex(id) {
|
|
return this.filesInProgress.findIndex((file) => file.id === id)
|
|
},
|
|
},
|
|
}
|
|
</script>
|