From 2c50153618cbbf227704a274cfc46e0ec071b525 Mon Sep 17 00:00:00 2001 From: Carl Schwan Date: Wed, 19 Oct 2022 15:15:12 +0200 Subject: [PATCH] Port files_versions to vue Simplify code and make it use our standard components Signed-off-by: Carl Schwan --- apps/files_versions/src/css/versions.css | 74 ------ apps/files_versions/src/files_versions.js | 29 --- apps/files_versions/src/files_versions_tab.js | 63 +++++ apps/files_versions/src/filesplugin.js | 46 ---- .../src/templates/item.handlebars | 22 -- .../src/templates/template.handlebars | 10 - apps/files_versions/src/versioncollection.js | 97 -------- apps/files_versions/src/versionmodel.js | 86 ------- apps/files_versions/src/versionstabview.js | 231 ------------------ apps/files_versions/src/views/VersionTab.vue | 222 +++++++++++++++++ webpack.modules.js | 2 +- 11 files changed, 286 insertions(+), 596 deletions(-) delete mode 100644 apps/files_versions/src/css/versions.css delete mode 100644 apps/files_versions/src/files_versions.js create mode 100644 apps/files_versions/src/files_versions_tab.js delete mode 100644 apps/files_versions/src/filesplugin.js delete mode 100644 apps/files_versions/src/templates/item.handlebars delete mode 100644 apps/files_versions/src/templates/template.handlebars delete mode 100644 apps/files_versions/src/versioncollection.js delete mode 100644 apps/files_versions/src/versionmodel.js delete mode 100644 apps/files_versions/src/versionstabview.js create mode 100644 apps/files_versions/src/views/VersionTab.vue diff --git a/apps/files_versions/src/css/versions.css b/apps/files_versions/src/css/versions.css deleted file mode 100644 index 8a32b143f03..00000000000 --- a/apps/files_versions/src/css/versions.css +++ /dev/null @@ -1,74 +0,0 @@ -.versionsTabView .clear-float { - clear: both; -} - -.versionsTabView li { - width: 100%; - cursor: default; - height: 56px; - float: left; - border-bottom: 1px solid rgba(100,100,100,.1); -} -.versionsTabView li:last-child { - border-bottom: none; -} - -.versionsTabView a, -.versionsTabView div > span { - vertical-align: middle; - opacity: .5; -} - -.versionsTabView li a{ - padding: 15px 10px 11px; -} - -.versionsTabView a:hover, -.versionsTabView a:focus { - opacity: 1; -} - -.versionsTabView .preview-container { - display: inline-block; - vertical-align: top; -} - -.versionsTabView .version-container img, .revertVersion img { - filter: var(--background-invert-if-dark); -} - -.versionsTabView img { - cursor: pointer; - padding-right: 4px; -} - -.versionsTabView img.preview { - cursor: default; -} - -.versionsTabView .version-container { - display: inline-block; -} - -.versionsTabView .versiondate { - min-width: 100px; - vertical-align: super; -} - -.versionsTabView .version-details { - text-align: left; -} - -.versionsTabView .version-details > span { - padding: 0 10px; -} - -.versionsTabView .revertVersion { - cursor: pointer; - float: right; - margin-right: -10px; -} - -.versionsTabView .emptycontent { - margin-top: 50px !important; -} diff --git a/apps/files_versions/src/files_versions.js b/apps/files_versions/src/files_versions.js deleted file mode 100644 index 9f4ccc2c1bf..00000000000 --- a/apps/files_versions/src/files_versions.js +++ /dev/null @@ -1,29 +0,0 @@ -/** - * @copyright Copyright (c) 2016 Roeland Jago Douma - * - * @author Roeland Jago Douma - * - * @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 . - * - */ - -import './versionmodel' -import './versioncollection' -import './versionstabview' -import './filesplugin' -import './css/versions.css' - -window.OCA.Versions = OCA.Versions diff --git a/apps/files_versions/src/files_versions_tab.js b/apps/files_versions/src/files_versions_tab.js new file mode 100644 index 00000000000..0e8f5b29838 --- /dev/null +++ b/apps/files_versions/src/files_versions_tab.js @@ -0,0 +1,63 @@ +/** + * @copyright 2022 Carl Schwan + * @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 . + * + */ + +import Vue from 'vue' +import { translate as t, translatePlural as n } from '@nextcloud/l10n' + +import VersionTab from './views/VersionTab.vue' +import VTooltip from 'v-tooltip' + +Vue.prototype.t = t +Vue.prototype.n = n + +Vue.use(VTooltip) + +// Init Sharing tab component +const View = Vue.extend(VersionTab) +let TabInstance = null + +window.addEventListener('DOMContentLoaded', function() { + if (OCA.Files && OCA.Files.Sidebar) { + OCA.Files.Sidebar.registerTab(new OCA.Files.Sidebar.Tab({ + id: 'version_vue', + name: t('files_versions', 'Version'), + icon: 'icon-history', + + async mount(el, fileInfo, context) { + if (TabInstance) { + TabInstance.$destroy() + } + TabInstance = new View({ + // Better integration with vue parent component + parent: context, + }) + // Only mount after we have all the info we need + await TabInstance.update(fileInfo) + TabInstance.$mount(el) + }, + update(fileInfo) { + TabInstance.update(fileInfo) + }, + destroy() { + TabInstance.$destroy() + TabInstance = null + }, + })) + } +}) diff --git a/apps/files_versions/src/filesplugin.js b/apps/files_versions/src/filesplugin.js deleted file mode 100644 index 90dac2024c1..00000000000 --- a/apps/files_versions/src/filesplugin.js +++ /dev/null @@ -1,46 +0,0 @@ -/** - * Copyright (c) 2015 - * - * @author John Molakvoæ - * @author Vincent Petry - * - * @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 . - * - */ - -(function() { - OCA.Versions = OCA.Versions || {} - - /** - * @namespace - */ - OCA.Versions.Util = { - /** - * Initialize the versions plugin. - * - * @param {OCA.Files.FileList} fileList file list to be extended - */ - attach(fileList) { - if (fileList.id === 'trashbin' || fileList.id === 'files.public') { - return - } - - fileList.registerTabView(new OCA.Versions.VersionsTabView('versionsTabView', { order: -10 })) - }, - } -})() - -OC.Plugins.register('OCA.Files.FileList', OCA.Versions.Util) diff --git a/apps/files_versions/src/templates/item.handlebars b/apps/files_versions/src/templates/item.handlebars deleted file mode 100644 index 656cab22866..00000000000 --- a/apps/files_versions/src/templates/item.handlebars +++ /dev/null @@ -1,22 +0,0 @@ -
  • -
    -
    - -
    -
    - - {{#hasDetails}} -
    - {{humanReadableSize}} -
    - {{/hasDetails}} -
    - {{#canRevert}} - - {{/canRevert}} -
    -
  • diff --git a/apps/files_versions/src/templates/template.handlebars b/apps/files_versions/src/templates/template.handlebars deleted file mode 100644 index f01a6f41626..00000000000 --- a/apps/files_versions/src/templates/template.handlebars +++ /dev/null @@ -1,10 +0,0 @@ -
      -
      - - - diff --git a/apps/files_versions/src/versioncollection.js b/apps/files_versions/src/versioncollection.js deleted file mode 100644 index 592b4f8cda2..00000000000 --- a/apps/files_versions/src/versioncollection.js +++ /dev/null @@ -1,97 +0,0 @@ -/** - * Copyright (c) 2015 - * - * @author John Molakvoæ - * @author Robin Appelman - * @author Vincent Petry - * - * @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 . - * - */ - -(function() { - /** - * @memberof OCA.Versions - */ - const VersionCollection = OC.Backbone.Collection.extend({ - model: OCA.Versions.VersionModel, - sync: OC.Backbone.davSync, - - /** - * @member OCA.Files.FileInfoModel - */ - _fileInfo: null, - - _currentUser: null, - - _client: null, - - setFileInfo(fileInfo) { - this._fileInfo = fileInfo - }, - - getFileInfo() { - return this._fileInfo - }, - - setCurrentUser(user) { - this._currentUser = user - }, - - getCurrentUser() { - return this._currentUser || OC.getCurrentUser().uid - }, - - setClient(client) { - this._client = client - }, - - getClient() { - return this._client || new OC.Files.Client({ - host: OC.getHost(), - root: OC.linkToRemoteBase('dav') + '/versions/' + this.getCurrentUser(), - useHTTPS: OC.getProtocol() === 'https', - }) - }, - - url() { - return OC.linkToRemoteBase('dav') + '/versions/' + this.getCurrentUser() + '/versions/' + this._fileInfo.get('id') - }, - - parse(result) { - const fullPath = this._fileInfo.getFullPath() - const fileId = this._fileInfo.get('id') - const name = this._fileInfo.get('name') - const user = this.getCurrentUser() - const client = this.getClient() - return _.map(result, function(version) { - version.fullPath = fullPath - version.fileId = fileId - version.name = name - version.timestamp = parseInt(moment(new Date(version.timestamp)).format('X'), 10) - version.id = OC.basename(version.href) - version.size = parseInt(version.size, 10) - version.user = user - version.client = client - return version - }) - }, - }) - - OCA.Versions = OCA.Versions || {} - - OCA.Versions.VersionCollection = VersionCollection -})() diff --git a/apps/files_versions/src/versionmodel.js b/apps/files_versions/src/versionmodel.js deleted file mode 100644 index 01914f702e2..00000000000 --- a/apps/files_versions/src/versionmodel.js +++ /dev/null @@ -1,86 +0,0 @@ -/** - * Copyright (c) 2015 - * - * @author John Molakvoæ - * @author Robin Appelman - * @author Vincent Petry - * - * @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 . - * - */ - -(function() { - /** - * @memberof OCA.Versions - */ - const VersionModel = OC.Backbone.Model.extend({ - sync: OC.Backbone.davSync, - - davProperties: { - size: '{DAV:}getcontentlength', - mimetype: '{DAV:}getcontenttype', - timestamp: '{DAV:}getlastmodified', - }, - - /** - * Restores the original file to this revision - * - * @param {object} [options] options - * @return {Promise} - */ - revert(options) { - options = options ? _.clone(options) : {} - const model = this - - const client = this.get('client') - - return client.move('/versions/' + this.get('fileId') + '/' + this.get('id'), '/restore/target', true) - .done(function() { - if (options.success) { - options.success.call(options.context, model, {}, options) - } - model.trigger('revert', model, options) - }) - .fail(function() { - if (options.error) { - options.error.call(options.context, model, {}, options) - } - model.trigger('error', model, {}, options) - }) - }, - - getFullPath() { - return this.get('fullPath') - }, - - getPreviewUrl() { - const url = OC.generateUrl('/apps/files_versions/preview') - const params = { - file: this.get('fullPath'), - version: this.get('id'), - } - return url + '?' + OC.buildQueryString(params) - }, - - getDownloadUrl() { - return OC.linkToRemoteBase('dav') + '/versions/' + this.get('user') + '/versions/' + this.get('fileId') + '/' + this.get('id') - }, - }) - - OCA.Versions = OCA.Versions || {} - - OCA.Versions.VersionModel = VersionModel -})() diff --git a/apps/files_versions/src/versionstabview.js b/apps/files_versions/src/versionstabview.js deleted file mode 100644 index 9f76755a582..00000000000 --- a/apps/files_versions/src/versionstabview.js +++ /dev/null @@ -1,231 +0,0 @@ -/** - * Copyright (c) 2015 - * - * @author Jan-Christoph Borchardt - * @author John Molakvoæ - * @author Julius Härtl - * @author Michael Jobst - * @author noveens - * @author Robin Appelman - * @author Vincent Petry - * - * @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 . - * - */ - -import ItemTemplate from './templates/item.handlebars' -import Template from './templates/template.handlebars'; - -(function() { - if (!OCA.Files.DetailTabView) { - // Only register the versions tab within the files app - return - } - /** - * @memberof OCA.Versions - */ - const VersionsTabView = OCA.Files.DetailTabView.extend(/** @lends OCA.Versions.VersionsTabView.prototype */{ - id: 'versionsTabView', - className: 'tab versionsTabView', - - _template: null, - - $versionsContainer: null, - - events: { - 'click .revertVersion': '_onClickRevertVersion', - }, - - initialize() { - OCA.Files.DetailTabView.prototype.initialize.apply(this, arguments) - this.collection = new OCA.Versions.VersionCollection() - this.collection.on('request', this._onRequest, this) - this.collection.on('sync', this._onEndRequest, this) - this.collection.on('update', this._onUpdate, this) - this.collection.on('error', this._onError, this) - this.collection.on('add', this._onAddModel, this) - }, - - getLabel() { - return t('files_versions', 'Versions') - }, - - getIcon() { - return 'icon-history' - }, - - nextPage() { - if (this._loading) { - return - } - - if (this.collection.getFileInfo() && this.collection.getFileInfo().isDirectory()) { - return - } - this.collection.fetch() - }, - - _onClickRevertVersion(ev) { - const self = this - let $target = $(ev.target) - const fileInfoModel = this.collection.getFileInfo() - if (!$target.is('li')) { - $target = $target.closest('li') - } - - ev.preventDefault() - const revision = $target.attr('data-revision') - - const versionModel = this.collection.get(revision) - versionModel.revert({ - success() { - // reset and re-fetch the updated collection - self.$versionsContainer.empty() - self.collection.setFileInfo(fileInfoModel) - self.collection.reset([], { silent: true }) - self.collection.fetch() - - self.$el.find('.versions').removeClass('hidden') - - // update original model - fileInfoModel.trigger('busy', fileInfoModel, false) - fileInfoModel.set({ - size: versionModel.get('size'), - mtime: versionModel.get('timestamp') * 1000, - // temp dummy, until we can do a PROPFIND - etag: versionModel.get('id') + versionModel.get('timestamp'), - }) - }, - - error() { - fileInfoModel.trigger('busy', fileInfoModel, false) - self.$el.find('.versions').removeClass('hidden') - self._toggleLoading(false) - OC.Notification.show(t('files_version', 'Failed to revert {file} to revision {timestamp}.', - { - file: versionModel.getFullPath(), - timestamp: OC.Util.formatDate(versionModel.get('timestamp') * 1000), - }), - { - type: 'error', - } - ) - }, - }) - - // spinner - this._toggleLoading(true) - fileInfoModel.trigger('busy', fileInfoModel, true) - }, - - _toggleLoading(state) { - this._loading = state - this.$el.find('.loading').toggleClass('hidden', !state) - }, - - _onRequest() { - this._toggleLoading(true) - }, - - _onEndRequest() { - this._toggleLoading(false) - this.$el.find('.empty').toggleClass('hidden', !!this.collection.length) - }, - - _onAddModel(model) { - const $el = $(this.itemTemplate(this._formatItem(model))) - this.$versionsContainer.append($el) - $el.find('.has-tooltip').tooltip() - }, - - template(data) { - return Template(data) - }, - - itemTemplate(data) { - return ItemTemplate(data) - }, - - setFileInfo(fileInfo) { - if (fileInfo) { - this.render() - this.collection.setFileInfo(fileInfo) - this.collection.reset([], { silent: true }) - this.nextPage() - } else { - this.render() - this.collection.reset() - } - }, - - _formatItem(version) { - const timestamp = version.get('timestamp') * 1000 - const size = version.has('size') ? version.get('size') : 0 - const preview = OC.MimeType.getIconUrl(version.get('mimetype')) - const img = new Image() - img.onload = function() { - $('li[data-revision=' + version.get('id') + '] .preview').attr('src', version.getPreviewUrl()) - } - img.src = version.getPreviewUrl() - - return _.extend({ - versionId: version.get('id'), - formattedTimestamp: OC.Util.formatDate(timestamp), - relativeTimestamp: OC.Util.relativeModifiedDate(timestamp), - millisecondsTimestamp: timestamp, - humanReadableSize: OC.Util.humanFileSize(size, true), - altSize: n('files', '%n byte', '%n bytes', size), - hasDetails: version.has('size'), - downloadUrl: version.getDownloadUrl(), - downloadIconUrl: OC.imagePath('core', 'actions/download'), - downloadName: version.get('name'), - revertIconUrl: OC.imagePath('core', 'actions/history'), - previewUrl: preview, - revertLabel: t('files_versions', 'Restore'), - canRevert: (this.collection.getFileInfo().get('permissions') & OC.PERMISSION_UPDATE) !== 0, - }, version.attributes) - }, - - /** - * Renders this details view - */ - render() { - this.$el.html(this.template({ - emptyResultLabel: t('files_versions', 'No other versions available'), - })) - this.$el.find('.has-tooltip').tooltip() - this.$versionsContainer = this.$el.find('ul.versions') - this.delegateEvents() - }, - - /** - * Returns true for files, false for folders. - * - * @param {FileInfo} fileInfo fileInfo - * @return {boolean} true for files, false for folders - */ - canDisplay(fileInfo) { - if (!fileInfo) { - return false - } - return !fileInfo.isDirectory() - }, - }) - - OCA.Versions = OCA.Versions || {} - - OCA.Versions.VersionsTabView = VersionsTabView -})() 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 @@ + + + + + + diff --git a/webpack.modules.js b/webpack.modules.js index f0788ab54f8..75524e2fa7f 100644 --- a/webpack.modules.js +++ b/webpack.modules.js @@ -65,7 +65,7 @@ module.exports = { files_trashbin: path.join(__dirname, 'apps/files_trashbin/src', 'files_trashbin.js'), }, files_versions: { - files_versions: path.join(__dirname, 'apps/files_versions/src', 'files_versions.js'), + files_versions: path.join(__dirname, 'apps/files_versions/src', 'files_versions_tab.js'), }, oauth2: { oauth2: path.join(__dirname, 'apps/oauth2/src', 'main.js'),