calendar/src/components/Editor/Attachments/AttachmentsList.vue

274 lines
6.9 KiB
Vue

<template>
<div id="attachments">
<input ref="localAttachments"
class="attachments-input"
type="file"
multiple
@change="onLocalAttachmentSelected">
<div class="attachments-summary">
<div class="attachments-summary-inner">
<Paperclip :size="20" />
<div v-if="attachments.length > 0" class="attachments-summary-inner-label">
{{ n('calendar', '{count} attachment', '{count} attachments', attachments.length, { count: attachments.length }) }}
</div>
<div v-else class="attachments-summary-inner-label">
{{ t('calendar', 'No attachments') }}
</div>
</div>
<NcActions v-if="!isReadOnly">
<template #icon>
<Plus :size="20" />
</template>
<NcActionButton @click="openFilesModal()">
<template #icon>
<Folder :size="20" />
</template>
{{ t('calendar', 'Add from Files') }}
</NcActionButton>
<NcActionButton @click="clickOnUploadButton">
<template #icon>
<Upload :size="20" />
</template>
{{ t('calendar', 'Upload from device') }}
</NcActionButton>
</NcActions>
</div>
<div v-if="attachments.length > 0">
<ul class="attachments-list">
<NcListItem v-for="attachment in attachments"
:key="attachment.path"
class="attachments-list-item"
:force-display-actions="true"
:name="getBaseName(attachment.fileName)"
@click="openFile(attachment.uri)">
<template #icon>
<img :src="getPreview(attachment)" class="attachment-icon">
</template>
<template #actions>
<NcActionButton v-if="!isReadOnly"
@click="deleteAttachmentFromEvent(attachment)">
<template #icon>
<Close :size="20" />
</template>
{{ t('calendar', 'Delete file') }}
</NcActionButton>
</template>
</NcListItem>
</ul>
</div>
</div>
</template>
<script>
import {
NcListItem,
NcActions,
NcActionButton,
} from '@nextcloud/vue'
import Upload from 'vue-material-design-icons/Upload.vue'
import Close from 'vue-material-design-icons/Close.vue'
import Folder from 'vue-material-design-icons/Folder.vue'
import Paperclip from 'vue-material-design-icons/Paperclip.vue'
import Plus from 'vue-material-design-icons/Plus.vue'
import { generateUrl } from '@nextcloud/router'
import { getFilePickerBuilder, showError } from '@nextcloud/dialogs'
import logger from '../../../utils/logger.js'
import {
uploadLocalAttachment,
getFileInfo,
} from '../../../services/attachmentService.js'
import { parseXML } from 'webdav'
export default {
name: 'AttachmentsList',
components: {
NcListItem,
NcActions,
NcActionButton,
Upload,
Close,
Folder,
Paperclip,
Plus,
},
props: {
calendarObjectInstance: {
type: Object,
required: true,
},
isReadOnly: {
type: Boolean,
default: true,
},
},
data() {
return {
uploading: false,
}
},
computed: {
currentUser() {
return this.$store.getters.getCurrentUserPrincipal
},
attachments() {
return this.calendarObjectInstance.attachments
},
},
methods: {
addAttachmentWithProperty(calendarObjectInstance, sharedData) {
this.$store.commit('addAttachmentWithProperty', {
calendarObjectInstance,
sharedData,
})
},
deleteAttachmentFromEvent(attachment) {
this.$store.commit('deleteAttachment', {
calendarObjectInstance: this.calendarObjectInstance,
attachment,
})
},
async openFilesModal() {
const picker = getFilePickerBuilder(t('calendar', 'Choose a file to add as attachment')).setMultiSelect(false).build()
try {
const filename = await picker.pick(t('calendar', 'Choose a file to share as a link'))
if (!this.isDuplicateAttachment(filename)) {
// TODO do not share Move this to PHP
const data = await getFileInfo(filename, this.currentUser.dav.userId)
const davRes = await parseXML(data)
const davRespObj = davRes?.multistatus?.response[0]?.propstat?.prop
davRespObj.fileName = filename
davRespObj.url = generateUrl(`/f/${davRespObj.fileid}`)
davRespObj.value = davRespObj.url
this.addAttachmentWithProperty(this.calendarObjectInstance, davRespObj)
}
} catch (error) {
}
},
isDuplicateAttachment(path) {
return this.attachments.find(attachment => {
if (attachment.fileName === path) {
showError(t('calendar', 'Attachment {name} already exist!', { name: this.getBaseName(path) }))
return true
}
return false
})
},
clickOnUploadButton() {
this.$refs.localAttachments.click()
},
async onLocalAttachmentSelected(e) {
try {
const attachmentsFolder = await this.$store.dispatch('createAttachmentsFolder')
const attachments = await uploadLocalAttachment(attachmentsFolder, Array.from(e.target.files), this.currentUser.dav, this.attachments)
// TODO do not share file, move to PHP
attachments.map(async attachment => {
const data = await getFileInfo(`${attachmentsFolder}/${attachment.path}`, this.currentUser.dav.userId)
const davRes = await parseXML(data)
const davRespObj = davRes?.multistatus?.response[0]?.propstat?.prop
davRespObj.fileName = attachment.path
davRespObj.url = generateUrl(`/f/${davRespObj.fileid}`)
davRespObj.value = davRespObj.url
this.addAttachmentWithProperty(this.calendarObjectInstance, davRespObj)
})
e.target.value = ''
} catch (error) {
logger.error('Could not upload attachment(s)', { error })
showError(t('calendar', 'Could not upload attachment(s)'))
}
},
getIcon(mime) {
return OC.MimeType.getIconUrl(mime)
},
getPreview(attachment) {
if (attachment.xNcHasPreview) {
return generateUrl(`/core/preview?fileId=${attachment.xNcFileId}&x=100&y=100&a=0`)
}
return attachment.formatType ? OC.MimeType.getIconUrl(attachment.formatType) : null
},
getBaseName(name) {
return name.split('/').pop()
},
openFile(url) {
window.open(url, '_blank', 'noopener noreferrer')
},
},
}
</script>
<style lang="scss" scoped>
.attachments-input {
display: none;
}
.attachments-summary {
display:flex;
align-items: center;
justify-content: space-between;
padding-left: 6px;
.attachments-summary-inner {
display:flex;
align-items: center;
span {
width: 34px;
height: 34px;
margin-left: -10px;
margin-right: 5px;
}
.attachments-summary-inner-label {
padding: 0 7px;
font-weight: bold;
}
}
}
.attachments-list {
margin: 0 -8px;
.attachments-list-item {
// Reduce height to 44px
:deep(.list-item) {
padding: 0 8px;
}
:deep(.list-item-content__wrapper) {
height: 44px;
}
:deep(.list-item-content) {
// Align text with other properties
padding-left: 18px;
}
:deep(.line-one__title) {
font-weight: unset;
}
}
}
#attachments .empty-content {
margin-top: 1rem;
text-align: center;
}
.button-group {
display: flex;
align-content: center;
justify-content: center;
button:first-child {
margin-right: 6px;
}
}
.attachment-icon {
width: 24px;
height: 24px;
border-radius: var(--border-radius);
}
</style>