diff options
Diffstat (limited to 'apps/files_versions/src/components/Version.vue')
-rw-r--r-- | apps/files_versions/src/components/Version.vue | 302 |
1 files changed, 302 insertions, 0 deletions
diff --git a/apps/files_versions/src/components/Version.vue b/apps/files_versions/src/components/Version.vue new file mode 100644 index 00000000000..a06d6a0ba8e --- /dev/null +++ b/apps/files_versions/src/components/Version.vue @@ -0,0 +1,302 @@ +<!-- + - @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"> + <template #icon> + <img lazy="true" + :src="previewURL" + alt="" + height="256" + width="256" + class="version__image"> + </template> + <template #subtitle> + <div class="version__info"> + <span v-tooltip="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" + :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' +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 } 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 } }), + } + }, + computed: { + /** + * @return {string} + */ + versionLabel() { + if (this.isCurrent) { + if (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 joinPaths('/remote.php/webdav', this.fileInfo.path, this.fileInfo.name) + } else { + return 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 + } + }, + }, + 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) + }, + + formattedDate() { + return moment(this.version.mtime) + }, + }, +} +</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> |