mirror of https://github.com/nextcloud/server.git
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
305 lines
7.6 KiB
Vue
305 lines
7.6 KiB
Vue
<!--
|
|
- @copyright 2022 Carl Schwan <carl@carlschwan.eu>
|
|
- @license AGPL-3.0-or-later
|
|
-
|
|
- This program is free software: you can redistribute it and/or modify
|
|
- it under the terms of the GNU Affero General Public License as
|
|
- published by the Free Software Foundation, either version 3 of the
|
|
- License, or (at your option) any later version.
|
|
-
|
|
- This program is distributed in the hope that it will be useful,
|
|
- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
- GNU Affero General Public License for more details.
|
|
-
|
|
- You should have received a copy of the GNU Affero General Public License
|
|
- along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
-->
|
|
<template>
|
|
<div>
|
|
<NcListItem class="version"
|
|
:title="versionLabel"
|
|
:href="downloadURL"
|
|
:force-display-actions="true"
|
|
data-files-versions-version>
|
|
<template #icon>
|
|
<img lazy="true"
|
|
:src="previewURL"
|
|
alt=""
|
|
height="256"
|
|
width="256"
|
|
class="version__image">
|
|
</template>
|
|
<template #subtitle>
|
|
<div class="version__info">
|
|
<span :title="formattedDate">{{ version.mtime | humanDateFromNow }}</span>
|
|
<!-- Separate dot to improve alignement -->
|
|
<span class="version__info__size">•</span>
|
|
<span class="version__info__size">{{ version.size | humanReadableSize }}</span>
|
|
</div>
|
|
</template>
|
|
<template #actions>
|
|
<NcActionButton v-if="capabilities.files.version_labeling === true"
|
|
:close-after-click="true"
|
|
@click="openVersionLabelModal">
|
|
<template #icon>
|
|
<Pencil :size="22" />
|
|
</template>
|
|
{{ version.label === '' ? t('files_versions', 'Name this version') : t('files_versions', 'Edit version name') }}
|
|
</NcActionButton>
|
|
<NcActionButton v-if="!isCurrent"
|
|
:close-after-click="true"
|
|
@click="restoreVersion">
|
|
<template #icon>
|
|
<BackupRestore :size="22" />
|
|
</template>
|
|
{{ t('files_versions', 'Restore version') }}
|
|
</NcActionButton>
|
|
<NcActionLink :href="downloadURL"
|
|
:close-after-click="true"
|
|
:download="downloadURL">
|
|
<template #icon>
|
|
<Download :size="22" />
|
|
</template>
|
|
{{ t('files_versions', 'Download version') }}
|
|
</NcActionLink>
|
|
<NcActionButton v-if="!isCurrent && capabilities.files.version_deletion === true"
|
|
:close-after-click="true"
|
|
@click="deleteVersion">
|
|
<template #icon>
|
|
<Delete :size="22" />
|
|
</template>
|
|
{{ t('files_versions', 'Delete version') }}
|
|
</NcActionButton>
|
|
</template>
|
|
</NcListItem>
|
|
<NcModal v-if="showVersionLabelForm"
|
|
:title="t('files_versions', 'Name this version')"
|
|
@close="showVersionLabelForm = false">
|
|
<form class="version-label-modal"
|
|
@submit.prevent="setVersionLabel(formVersionLabelValue)">
|
|
<label>
|
|
<div class="version-label-modal__title">{{ t('photos', 'Version name') }}</div>
|
|
<NcTextField ref="labelInput"
|
|
:value.sync="formVersionLabelValue"
|
|
:placeholder="t('photos', 'Version name')"
|
|
:label-outside="true" />
|
|
</label>
|
|
|
|
<div class="version-label-modal__info">
|
|
{{ t('photos', 'Named versions are persisted, and excluded from automatic cleanups when your storage quota is full.') }}
|
|
</div>
|
|
|
|
<div class="version-label-modal__actions">
|
|
<NcButton :disabled="formVersionLabelValue.trim().length === 0" @click="setVersionLabel('')">
|
|
{{ t('files_versions', 'Remove version name') }}
|
|
</NcButton>
|
|
<NcButton type="primary" native-type="submit">
|
|
<template #icon>
|
|
<Check />
|
|
</template>
|
|
{{ t('files_versions', 'Save version name') }}
|
|
</NcButton>
|
|
</div>
|
|
</form>
|
|
</NcModal>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import BackupRestore from 'vue-material-design-icons/BackupRestore.vue'
|
|
import Download from 'vue-material-design-icons/Download.vue'
|
|
import Pencil from 'vue-material-design-icons/Pencil.vue'
|
|
import Check from 'vue-material-design-icons/Check.vue'
|
|
import Delete from 'vue-material-design-icons/Delete.vue'
|
|
import { NcActionButton, NcActionLink, NcListItem, NcModal, NcButton, NcTextField, Tooltip } from '@nextcloud/vue'
|
|
import moment from '@nextcloud/moment'
|
|
import { translate } from '@nextcloud/l10n'
|
|
import { joinPaths } from '@nextcloud/paths'
|
|
import { generateUrl, getRootUrl } from '@nextcloud/router'
|
|
import { loadState } from '@nextcloud/initial-state'
|
|
|
|
export default {
|
|
name: 'Version',
|
|
components: {
|
|
NcActionLink,
|
|
NcActionButton,
|
|
NcListItem,
|
|
NcModal,
|
|
NcButton,
|
|
NcTextField,
|
|
BackupRestore,
|
|
Download,
|
|
Pencil,
|
|
Check,
|
|
Delete,
|
|
},
|
|
directives: {
|
|
tooltip: Tooltip,
|
|
},
|
|
filters: {
|
|
/**
|
|
* @param {number} bytes
|
|
* @return {string}
|
|
*/
|
|
humanReadableSize(bytes) {
|
|
return OC.Util.humanFileSize(bytes)
|
|
},
|
|
/**
|
|
* @param {number} timestamp
|
|
* @return {string}
|
|
*/
|
|
humanDateFromNow(timestamp) {
|
|
return moment(timestamp).fromNow()
|
|
},
|
|
},
|
|
props: {
|
|
/** @type {Vue.PropOptions<import('../utils/versions.js').Version>} */
|
|
version: {
|
|
type: Object,
|
|
required: true,
|
|
},
|
|
fileInfo: {
|
|
type: Object,
|
|
required: true,
|
|
},
|
|
isCurrent: {
|
|
type: Boolean,
|
|
default: false,
|
|
},
|
|
isFirstVersion: {
|
|
type: Boolean,
|
|
default: false,
|
|
},
|
|
},
|
|
data() {
|
|
return {
|
|
showVersionLabelForm: false,
|
|
formVersionLabelValue: this.version.label,
|
|
capabilities: loadState('core', 'capabilities', { files: { version_labeling: false, version_deletion: false } }),
|
|
}
|
|
},
|
|
computed: {
|
|
/**
|
|
* @return {string}
|
|
*/
|
|
versionLabel() {
|
|
if (this.isCurrent) {
|
|
if (this.version.label === undefined || this.version.label === '') {
|
|
return translate('files_versions', 'Current version')
|
|
} else {
|
|
return `${this.version.label} (${translate('files_versions', 'Current version')})`
|
|
}
|
|
}
|
|
|
|
if (this.isFirstVersion && this.version.label === '') {
|
|
return translate('files_versions', 'Initial version')
|
|
}
|
|
|
|
return this.version.label
|
|
},
|
|
|
|
/**
|
|
* @return {string}
|
|
*/
|
|
downloadURL() {
|
|
if (this.isCurrent) {
|
|
return getRootUrl() + joinPaths('/remote.php/webdav', this.fileInfo.path, this.fileInfo.name)
|
|
} else {
|
|
return getRootUrl() + this.version.url
|
|
}
|
|
},
|
|
|
|
/**
|
|
* @return {string}
|
|
*/
|
|
previewURL() {
|
|
if (this.isCurrent) {
|
|
return generateUrl('/core/preview?fileId={fileId}&c={fileEtag}&x=250&y=250&forceIcon=0&a=0', {
|
|
fileId: this.fileInfo.id,
|
|
fileEtag: this.fileInfo.etag,
|
|
})
|
|
} else {
|
|
return this.version.preview
|
|
}
|
|
},
|
|
|
|
/** @return {string} */
|
|
formattedDate() {
|
|
return moment(this.version.mtime).format('LLL')
|
|
},
|
|
},
|
|
methods: {
|
|
openVersionLabelModal() {
|
|
this.showVersionLabelForm = true
|
|
this.$nextTick(() => {
|
|
this.$refs.labelInput.$el.getElementsByTagName('input')[0].focus()
|
|
})
|
|
},
|
|
|
|
restoreVersion() {
|
|
this.$emit('restore', this.version)
|
|
},
|
|
|
|
setVersionLabel(label) {
|
|
this.formVersionLabelValue = label
|
|
this.showVersionLabelForm = false
|
|
this.$emit('label-update', this.version, label)
|
|
},
|
|
|
|
deleteVersion() {
|
|
this.$emit('delete', this.version)
|
|
},
|
|
},
|
|
}
|
|
</script>
|
|
|
|
<style scoped lang="scss">
|
|
.version {
|
|
display: flex;
|
|
flex-direction: row;
|
|
|
|
&__info {
|
|
display: flex;
|
|
flex-direction: row;
|
|
align-items: center;
|
|
gap: 0.5rem;
|
|
|
|
&__size {
|
|
color: var(--color-text-lighter);
|
|
}
|
|
}
|
|
|
|
&__image {
|
|
width: 3rem;
|
|
height: 3rem;
|
|
border: 1px solid var(--color-border);
|
|
border-radius: var(--border-radius-large);
|
|
}
|
|
}
|
|
|
|
.version-label-modal {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
flex-direction: column;
|
|
height: 250px;
|
|
padding: 16px;
|
|
|
|
&__title {
|
|
margin-bottom: 12px;
|
|
font-weight: 600;
|
|
}
|
|
|
|
&__info {
|
|
margin-top: 12px;
|
|
color: var(--color-text-maxcontrast);
|
|
}
|
|
|
|
&__actions {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
margin-top: 64px;
|
|
}
|
|
}
|
|
</style>
|