|
|
|
@ -21,6 +21,7 @@
|
|
|
|
|
:force-display-actions="true"
|
|
|
|
|
data-files-versions-version
|
|
|
|
|
@click="click">
|
|
|
|
|
<!-- Icon -->
|
|
|
|
|
<template #icon>
|
|
|
|
|
<div v-if="!(loadPreview || previewLoaded)" class="version__image" />
|
|
|
|
|
<img v-else-if="(isCurrent || version.hasPreview) && !previewErrored"
|
|
|
|
@ -37,6 +38,8 @@
|
|
|
|
|
<ImageOffOutline :size="20" />
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<!-- Version file size as subline -->
|
|
|
|
|
<template #subname>
|
|
|
|
|
<div class="version__info">
|
|
|
|
|
<span :title="formattedDate">{{ version.mtime | humanDateFromNow }}</span>
|
|
|
|
@ -45,6 +48,8 @@
|
|
|
|
|
<span class="version__info__size">{{ version.size | humanReadableSize }}</span>
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<!-- Actions -->
|
|
|
|
|
<template #actions>
|
|
|
|
|
<NcActionButton v-if="enableLabeling && hasUpdatePermissions"
|
|
|
|
|
:close-after-click="true"
|
|
|
|
@ -91,28 +96,34 @@
|
|
|
|
|
</NcListItem>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script>
|
|
|
|
|
<script lang="ts">
|
|
|
|
|
import type { Version } from '../utils/versions'
|
|
|
|
|
|
|
|
|
|
import BackupRestore from 'vue-material-design-icons/BackupRestore.vue'
|
|
|
|
|
import Delete from 'vue-material-design-icons/Delete.vue'
|
|
|
|
|
import Download from 'vue-material-design-icons/Download.vue'
|
|
|
|
|
import FileCompare from 'vue-material-design-icons/FileCompare.vue'
|
|
|
|
|
import Pencil from 'vue-material-design-icons/Pencil.vue'
|
|
|
|
|
import Delete from 'vue-material-design-icons/Delete.vue'
|
|
|
|
|
import ImageOffOutline from 'vue-material-design-icons/ImageOffOutline.vue'
|
|
|
|
|
import Pencil from 'vue-material-design-icons/Pencil.vue'
|
|
|
|
|
|
|
|
|
|
import NcActionButton from '@nextcloud/vue/dist/Components/NcActionButton.js'
|
|
|
|
|
import NcActionLink from '@nextcloud/vue/dist/Components/NcActionLink.js'
|
|
|
|
|
import NcListItem from '@nextcloud/vue/dist/Components/NcListItem.js'
|
|
|
|
|
import Tooltip from '@nextcloud/vue/dist/Directives/Tooltip.js'
|
|
|
|
|
import moment from '@nextcloud/moment'
|
|
|
|
|
import { translate as t } from '@nextcloud/l10n'
|
|
|
|
|
import { joinPaths } from '@nextcloud/paths'
|
|
|
|
|
|
|
|
|
|
import { defineComponent, type PropType } from 'vue'
|
|
|
|
|
import { getRootUrl } from '@nextcloud/router'
|
|
|
|
|
import { joinPaths } from '@nextcloud/paths'
|
|
|
|
|
import { loadState } from '@nextcloud/initial-state'
|
|
|
|
|
import { Permission } from '@nextcloud/files'
|
|
|
|
|
import { Permission, formatFileSize } from '@nextcloud/files'
|
|
|
|
|
import { translate as t } from '@nextcloud/l10n'
|
|
|
|
|
import moment from '@nextcloud/moment'
|
|
|
|
|
|
|
|
|
|
import { hasPermissions } from '../../../files_sharing/src/lib/SharePermissionsToolBox.js'
|
|
|
|
|
const hasPermission = (permissions: number, permission: number): boolean => (permissions & permission) !== 0
|
|
|
|
|
|
|
|
|
|
export default {
|
|
|
|
|
export default defineComponent({
|
|
|
|
|
name: 'Version',
|
|
|
|
|
|
|
|
|
|
components: {
|
|
|
|
|
NcActionLink,
|
|
|
|
|
NcActionButton,
|
|
|
|
@ -124,29 +135,24 @@ export default {
|
|
|
|
|
Delete,
|
|
|
|
|
ImageOffOutline,
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
directives: {
|
|
|
|
|
tooltip: Tooltip,
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
filters: {
|
|
|
|
|
/**
|
|
|
|
|
* @param {number} bytes
|
|
|
|
|
* @return {string}
|
|
|
|
|
*/
|
|
|
|
|
humanReadableSize(bytes) {
|
|
|
|
|
return OC.Util.humanFileSize(bytes)
|
|
|
|
|
humanReadableSize(bytes: number): string {
|
|
|
|
|
return formatFileSize(bytes)
|
|
|
|
|
},
|
|
|
|
|
/**
|
|
|
|
|
* @param {number} timestamp
|
|
|
|
|
* @return {string}
|
|
|
|
|
*/
|
|
|
|
|
humanDateFromNow(timestamp) {
|
|
|
|
|
|
|
|
|
|
humanDateFromNow(timestamp: number): string {
|
|
|
|
|
return moment(timestamp).fromNow()
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
props: {
|
|
|
|
|
/** @type {Vue.PropOptions<import('../utils/versions.ts').Version>} */
|
|
|
|
|
version: {
|
|
|
|
|
type: Object,
|
|
|
|
|
type: Object as PropType<Version>,
|
|
|
|
|
required: true,
|
|
|
|
|
},
|
|
|
|
|
fileInfo: {
|
|
|
|
@ -174,6 +180,9 @@ export default {
|
|
|
|
|
default: false,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
emits: ['click', 'compare', 'restore', 'delete', 'label-update-request'],
|
|
|
|
|
|
|
|
|
|
data() {
|
|
|
|
|
return {
|
|
|
|
|
previewLoaded: false,
|
|
|
|
@ -181,11 +190,9 @@ export default {
|
|
|
|
|
capabilities: loadState('core', 'capabilities', { files: { version_labeling: false, version_deletion: false } }),
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
computed: {
|
|
|
|
|
/**
|
|
|
|
|
* @return {string}
|
|
|
|
|
*/
|
|
|
|
|
versionLabel() {
|
|
|
|
|
versionLabel(): string {
|
|
|
|
|
const label = this.version.label ?? ''
|
|
|
|
|
|
|
|
|
|
if (this.isCurrent) {
|
|
|
|
@ -203,10 +210,7 @@ export default {
|
|
|
|
|
return label
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @return {string}
|
|
|
|
|
*/
|
|
|
|
|
downloadURL() {
|
|
|
|
|
downloadURL(): string {
|
|
|
|
|
if (this.isCurrent) {
|
|
|
|
|
return getRootUrl() + joinPaths('/remote.php/webdav', this.fileInfo.path, this.fileInfo.name)
|
|
|
|
|
} else {
|
|
|
|
@ -214,41 +218,37 @@ export default {
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
/** @return {string} */
|
|
|
|
|
formattedDate() {
|
|
|
|
|
formattedDate(): string {
|
|
|
|
|
return moment(this.version.mtime).format('LLL')
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
/** @return {boolean} */
|
|
|
|
|
enableLabeling() {
|
|
|
|
|
enableLabeling(): boolean {
|
|
|
|
|
return this.capabilities.files.version_labeling === true
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
/** @return {boolean} */
|
|
|
|
|
enableDeletion() {
|
|
|
|
|
enableDeletion(): boolean {
|
|
|
|
|
return this.capabilities.files.version_deletion === true
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
/** @return {boolean} */
|
|
|
|
|
hasDeletePermissions() {
|
|
|
|
|
return hasPermissions(this.fileInfo.permissions, Permission.DELETE)
|
|
|
|
|
hasDeletePermissions(): boolean {
|
|
|
|
|
return hasPermission(this.fileInfo.permissions, Permission.DELETE)
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
/** @return {boolean} */
|
|
|
|
|
hasUpdatePermissions() {
|
|
|
|
|
return hasPermissions(this.fileInfo.permissions, Permission.UPDATE)
|
|
|
|
|
hasUpdatePermissions(): boolean {
|
|
|
|
|
return hasPermission(this.fileInfo.permissions, Permission.UPDATE)
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
/** @return {boolean} */
|
|
|
|
|
isDownloadable() {
|
|
|
|
|
isDownloadable(): boolean {
|
|
|
|
|
if ((this.fileInfo.permissions & Permission.READ) === 0) {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If the mount type is a share, ensure it got download permissions.
|
|
|
|
|
if (this.fileInfo.mountType === 'shared') {
|
|
|
|
|
const downloadAttribute = this.fileInfo.shareAttributes.find((attribute) => attribute.scope === 'permissions' && attribute.key === 'download')
|
|
|
|
|
if (downloadAttribute !== undefined && downloadAttribute.enabled === false) {
|
|
|
|
|
const downloadAttribute = this.fileInfo.shareAttributes
|
|
|
|
|
.find((attribute) => attribute.scope === 'permissions' && attribute.key === 'download') || {}
|
|
|
|
|
// If the download attribute is set to false, the file is not downloadable
|
|
|
|
|
if (downloadAttribute?.enabled === false) {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -256,6 +256,7 @@ export default {
|
|
|
|
|
return true
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
methods: {
|
|
|
|
|
labelUpdate() {
|
|
|
|
|
this.$emit('label-update-request')
|
|
|
|
@ -286,7 +287,7 @@ export default {
|
|
|
|
|
|
|
|
|
|
t,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<style scoped lang="scss">
|
|
|
|
|