VersionTab.vue 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. <!--
  2. - @copyright 2022 Carl Schwan <carl@carlschwan.eu>
  3. - @license AGPL-3.0-or-later
  4. -
  5. - This program is free software: you can redistribute it and/or modify
  6. - it under the terms of the GNU Affero General Public License as
  7. - published by the Free Software Foundation, either version 3 of the
  8. - License, or (at your option) any later version.
  9. -
  10. - This program is distributed in the hope that it will be useful,
  11. - but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. - GNU Affero General Public License for more details.
  14. -
  15. - You should have received a copy of the GNU Affero General Public License
  16. - along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. -->
  18. <template>
  19. <div>
  20. <ul>
  21. <li v-for="version in versions" class="version">
  22. <img lazy="true"
  23. :src="version.preview"
  24. height="256"
  25. width="256"
  26. class="version-image">
  27. <div class="version-info">
  28. <a v-tooltip="version.dateTime" :href="version.url">{{ version.relativeTime }}</a>
  29. <div class="version-info-size">
  30. {{ version.size }}
  31. </div>
  32. </div>
  33. <NcButton v-tooltip="t('files_versions', `Download file ${fileInfo.name} with version ${version.displayVersionName}`)"
  34. type="secondary"
  35. class="download-button"
  36. :href="version.url"
  37. :aria-label="t('files_versions', `Download file ${fileInfo.name} with version ${version.displayVersionName}`)">
  38. <template #icon>
  39. <Download :size="22" />
  40. </template>
  41. </NcButton>
  42. <NcButton v-tooltip="t('files_versions', `Restore file ${fileInfo.name} with version ${version.displayVersionName}`)"
  43. type="secondary"
  44. class="restore-button"
  45. :aria-label="t('files_versions', `Restore file ${fileInfo.name} with version ${version.displayVersionName}`)"
  46. @click="restoreVersion(version)">
  47. <template #icon>
  48. <BackupRestore :size="22" />
  49. </template>
  50. </NcButton>
  51. </li>
  52. </ul>
  53. </div>
  54. </template>
  55. <script>
  56. import { createClient, getPatcher } from 'webdav'
  57. import axios from '@nextcloud/axios'
  58. import parseUrl from 'url-parse'
  59. import { generateRemoteUrl, generateUrl } from '@nextcloud/router'
  60. import { getCurrentUser } from '@nextcloud/auth'
  61. import { translate } from '@nextcloud/l10n'
  62. import BackupRestore from 'vue-material-design-icons/BackupRestore.vue'
  63. import Download from 'vue-material-design-icons/Download.vue'
  64. import NcButton from '@nextcloud/vue/dist/Components/NcButton.js'
  65. import { showError, showSuccess } from '@nextcloud/dialogs'
  66. import moment from '@nextcloud/moment'
  67. import { basename, joinPaths } from '@nextcloud/paths'
  68. /**
  69. *
  70. */
  71. function getDavRequest() {
  72. return `<?xml version="1.0"?>
  73. <d:propfind xmlns:d="DAV:"
  74. xmlns:oc="http://owncloud.org/ns"
  75. xmlns:nc="http://nextcloud.org/ns"
  76. xmlns:ocs="http://open-collaboration-services.org/ns">
  77. <d:prop>
  78. <d:getcontentlength />
  79. <d:getcontenttype />
  80. <d:getlastmodified />
  81. </d:prop>
  82. </d:propfind>`
  83. }
  84. /**
  85. *
  86. * @param version
  87. * @param fileInfo
  88. */
  89. function formatVersion(version, fileInfo) {
  90. const fileVersion = basename(version.filename)
  91. const preview = generateUrl('/apps/files_versions/preview?file={file}&version={fileVersion}', {
  92. file: joinPaths(fileInfo.path, fileInfo.name),
  93. fileVersion,
  94. })
  95. return {
  96. displayVersionName: fileVersion,
  97. fileName: version.filename,
  98. mimeType: version.mime,
  99. size: OC.Util.humanFileSize(version.size),
  100. type: version.type,
  101. dateTime: moment(version.lastmod),
  102. relativeTime: moment(version.lastmod).fromNow(),
  103. preview,
  104. url: joinPaths('/remote.php/dav', version.filename),
  105. fileVersion,
  106. }
  107. }
  108. export default {
  109. name: 'VersionTab',
  110. components: {
  111. NcButton,
  112. BackupRestore,
  113. Download,
  114. },
  115. data() {
  116. const rootPath = 'dav'
  117. // force our axios
  118. const patcher = getPatcher()
  119. patcher.patch('request', axios)
  120. // init webdav client on default dav endpoint
  121. const remote = generateRemoteUrl(rootPath)
  122. const client = createClient(remote)
  123. return {
  124. fileInfo: null,
  125. versions: [],
  126. client,
  127. remote,
  128. }
  129. },
  130. methods: {
  131. /**
  132. * Update current fileInfo and fetch new data
  133. *
  134. * @param {object} fileInfo the current file FileInfo
  135. */
  136. async update(fileInfo) {
  137. this.fileInfo = fileInfo
  138. this.resetState()
  139. this.fetchVersions()
  140. },
  141. /**
  142. * Get the existing versions infos
  143. */
  144. async fetchVersions() {
  145. const path = `/versions/${getCurrentUser().uid}/versions/${this.fileInfo.id}`
  146. const remotePath = parseUrl(this.remote).pathname
  147. const response = await this.client.getDirectoryContents(path, {
  148. data: getDavRequest(),
  149. })
  150. this.versions = response.filter(version => version.mime !== '')
  151. .map(version => formatVersion(version, this.fileInfo))
  152. },
  153. /**
  154. * Restore the given version
  155. *
  156. * @param version
  157. */
  158. async restoreVersion(version) {
  159. try {
  160. console.debug('restore version', version.url)
  161. const response = await this.client.moveFile(
  162. `/versions/${getCurrentUser().uid}/versions/${this.fileInfo.id}/${version.fileVersion}`,
  163. `/versions/${getCurrentUser().uid}/restore/target`
  164. )
  165. showSuccess(t('files_versions', 'Version restored'))
  166. await this.fetchVersions()
  167. } catch (exception) {
  168. console.error('Could not restore version', exception)
  169. showError(t('files_versions', 'Could not restore version'))
  170. }
  171. },
  172. /**
  173. * Reset the current view to its default state
  174. */
  175. resetState() {
  176. this.versions = []
  177. },
  178. },
  179. }
  180. </script>
  181. <style scopped lang="scss">
  182. .version {
  183. display: flex;
  184. flex-direction: row;
  185. &-info {
  186. display: flex;
  187. flex-direction: column;
  188. &-size {
  189. color: var(--color-text-lighter);
  190. }
  191. }
  192. &-image {
  193. width: 3rem;
  194. height: 3rem;
  195. filter: drop-shadow(0 1px 2px var(--color-box-shadow));
  196. margin-right: 1rem;
  197. border-radius: var(--border-radius);
  198. }
  199. .restore-button {
  200. margin-left: 1rem;
  201. align-self: center;
  202. }
  203. .download-button {
  204. margin-left: auto;
  205. align-self: center;
  206. }
  207. }
  208. </style>