summaryrefslogtreecommitdiffstats
path: root/apps/files_versions/src/views/VersionTab.vue
diff options
context:
space:
mode:
Diffstat (limited to 'apps/files_versions/src/views/VersionTab.vue')
-rw-r--r--apps/files_versions/src/views/VersionTab.vue222
1 files changed, 222 insertions, 0 deletions
diff --git a/apps/files_versions/src/views/VersionTab.vue b/apps/files_versions/src/views/VersionTab.vue
new file mode 100644
index 00000000000..f7162a3f9e1
--- /dev/null
+++ b/apps/files_versions/src/views/VersionTab.vue
@@ -0,0 +1,222 @@
+<!--
+ - @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>
+ <ul>
+ <li v-for="version in versions" class="version">
+ <img lazy="true"
+ :src="version.preview"
+ height="256"
+ width="256"
+ class="version-image">
+ <div class="version-info">
+ <a v-tooltip="version.dateTime" :href="version.url">{{ version.relativeTime }}</a>
+ <div class="version-info-size">
+ {{ version.size }}
+ </div>
+ </div>
+ <NcButton v-tooltip="t('files_versions', `Download file ${fileInfo.name} with version ${version.displayVersionName}`)"
+ type="secondary"
+ class="download-button"
+ :href="version.url"
+ :aria-label="t('files_versions', `Download file ${fileInfo.name} with version ${version.displayVersionName}`)">
+ <template #icon>
+ <Download :size="22" />
+ </template>
+ </NcButton>
+ <NcButton v-tooltip="t('files_versions', `Restore file ${fileInfo.name} with version ${version.displayVersionName}`)"
+ type="secondary"
+ class="restore-button"
+ :aria-label="t('files_versions', `Restore file ${fileInfo.name} with version ${version.displayVersionName}`)"
+ @click="restoreVersion(version)">
+ <template #icon>
+ <BackupRestore :size="22" />
+ </template>
+ </NcButton>
+ </li>
+ </ul>
+ </div>
+</template>
+
+<script>
+import { createClient, getPatcher } from 'webdav'
+import axios from '@nextcloud/axios'
+import parseUrl from 'url-parse'
+import { generateRemoteUrl, generateUrl } from '@nextcloud/router'
+import { getCurrentUser } from '@nextcloud/auth'
+import { translate } from '@nextcloud/l10n'
+import BackupRestore from 'vue-material-design-icons/BackupRestore.vue'
+import Download from 'vue-material-design-icons/Download.vue'
+import NcButton from '@nextcloud/vue/dist/Components/NcButton.js'
+import { showError, showSuccess } from '@nextcloud/dialogs'
+import moment from '@nextcloud/moment'
+import { basename, joinPaths } from '@nextcloud/paths'
+
+/**
+ *
+ */
+function getDavRequest() {
+ return `<?xml version="1.0"?>
+ <d:propfind xmlns:d="DAV:"
+ xmlns:oc="http://owncloud.org/ns"
+ xmlns:nc="http://nextcloud.org/ns"
+ xmlns:ocs="http://open-collaboration-services.org/ns">
+ <d:prop>
+ <d:getcontentlength />
+ <d:getcontenttype />
+ <d:getlastmodified />
+ </d:prop>
+ </d:propfind>`
+}
+
+/**
+ *
+ * @param version
+ * @param fileInfo
+ */
+function formatVersion(version, fileInfo) {
+ const fileVersion = basename(version.filename)
+
+ const preview = generateUrl('/apps/files_versions/preview?file={file}&version={fileVersion}', {
+ file: joinPaths(fileInfo.path, fileInfo.name),
+ fileVersion,
+ })
+
+ return {
+ displayVersionName: fileVersion,
+ fileName: version.filename,
+ mimeType: version.mime,
+ size: OC.Util.humanFileSize(version.size),
+ type: version.type,
+ dateTime: moment(version.lastmod),
+ relativeTime: moment(version.lastmod).fromNow(),
+ preview,
+ url: joinPaths('/remote.php/dav', version.filename),
+ fileVersion,
+ }
+}
+
+export default {
+ name: 'VersionTab',
+ components: {
+ NcButton,
+ BackupRestore,
+ Download,
+ },
+ data() {
+ const rootPath = 'dav'
+
+ // force our axios
+ const patcher = getPatcher()
+ patcher.patch('request', axios)
+
+ // init webdav client on default dav endpoint
+ const remote = generateRemoteUrl(rootPath)
+ const client = createClient(remote)
+
+ return {
+ fileInfo: null,
+ versions: [],
+ client,
+ remote,
+ }
+ },
+ methods: {
+ /**
+ * Update current fileInfo and fetch new data
+ *
+ * @param {object} fileInfo the current file FileInfo
+ */
+ async update(fileInfo) {
+ this.fileInfo = fileInfo
+ this.resetState()
+ this.fetchVersions()
+ },
+
+ /**
+ * Get the existing versions infos
+ */
+ async fetchVersions() {
+ const path = `/versions/${getCurrentUser().uid}/versions/${this.fileInfo.id}`
+ const remotePath = parseUrl(this.remote).pathname
+
+ const response = await this.client.getDirectoryContents(path, {
+ data: getDavRequest(),
+ })
+ this.versions = response.filter(version => version.mime !== '')
+ .map(version => formatVersion(version, this.fileInfo))
+ },
+
+ /**
+ * Restore the given version
+ *
+ * @param version
+ */
+ async restoreVersion(version) {
+ try {
+ console.debug('restore version', version.url)
+ const response = await this.client.moveFile(
+ `/versions/${getCurrentUser().uid}/versions/${this.fileInfo.id}/${version.fileVersion}`,
+ `/versions/${getCurrentUser().uid}/restore/target`
+ )
+ showSuccess(t('files_versions', 'Version restored'))
+ await this.fetchVersions()
+ } catch (exception) {
+ console.error('Could not restore version', exception)
+ showError(t('files_versions', 'Could not restore version'))
+ }
+ },
+
+ /**
+ * Reset the current view to its default state
+ */
+ resetState() {
+ this.versions = []
+ },
+ },
+}
+</script>
+
+<style scopped lang="scss">
+.version {
+ display: flex;
+ flex-direction: row;
+ &-info {
+ display: flex;
+ flex-direction: column;
+ &-size {
+ color: var(--color-text-lighter);
+ }
+ }
+ &-image {
+ width: 3rem;
+ height: 3rem;
+ filter: drop-shadow(0 1px 2px var(--color-box-shadow));
+ margin-right: 1rem;
+ border-radius: var(--border-radius);
+ }
+ .restore-button {
+ margin-left: 1rem;
+ align-self: center;
+ }
+ .download-button {
+ margin-left: auto;
+ align-self: center;
+ }
+}
+</style>