Skip to content

Commit a884f31

Browse files
authored
Merge pull request #34769 from nextcloud/port/vue/files_version
Port files_versions to vue
2 parents e450bc4 + 9d54b60 commit a884f31

36 files changed

+559
-986
lines changed

apps/comments/src/comments-tab.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,15 @@
2020
*
2121
*/
2222

23+
// eslint-disable-next-line node/no-missing-import, import/no-unresolved
24+
import MessageReplyText from '@mdi/svg/svg/message-reply-text.svg?raw'
25+
2326
// Init Comments tab component
2427
let TabInstance = null
2528
const commentTab = new OCA.Files.Sidebar.Tab({
2629
id: 'comments',
2730
name: t('comments', 'Comments'),
28-
icon: 'icon-comment',
31+
iconSvg: MessageReplyText,
2932

3033
async mount(el, fileInfo, context) {
3134
if (TabInstance) {

apps/files/src/components/SidebarTab.vue

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@
2626
:name="name"
2727
:icon="icon"
2828
@bottomReached="onScrollBottomReached">
29+
<template #icon>
30+
<slot name="icon" />
31+
</template>
2932
<!-- Fallback loading -->
3033
<NcEmptyContent v-if="loading" icon="icon-loading" />
3134

@@ -63,7 +66,7 @@ export default {
6366
},
6467
icon: {
6568
type: String,
66-
required: true,
69+
required: false,
6770
},
6871
6972
/**

apps/files/src/models/Tab.js

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,14 @@
1919
* along with this program. If not, see <http://www.gnu.org/licenses/>.
2020
*
2121
*/
22+
import { sanitizeSVG } from '@skjnldsv/sanitize-svg'
2223

2324
export default class Tab {
2425

2526
_id
2627
_name
2728
_icon
29+
_iconSvgSanitized
2830
_mount
2931
_update
3032
_destroy
@@ -37,19 +39,20 @@ export default class Tab {
3739
* @param {object} options destructuring object
3840
* @param {string} options.id the unique id of this tab
3941
* @param {string} options.name the translated tab name
40-
* @param {string} options.icon the vue component
42+
* @param {?string} options.icon the icon css class
43+
* @param {?string} options.iconSvg the icon in svg format
4144
* @param {Function} options.mount function to mount the tab
4245
* @param {Function} options.update function to update the tab
4346
* @param {Function} options.destroy function to destroy the tab
4447
* @param {Function} [options.enabled] define conditions whether this tab is active. Must returns a boolean
4548
* @param {Function} [options.scrollBottomReached] executed when the tab is scrolled to the bottom
4649
*/
47-
constructor({ id, name, icon, mount, update, destroy, enabled, scrollBottomReached } = {}) {
50+
constructor({ id, name, icon, iconSvg, mount, update, destroy, enabled, scrollBottomReached } = {}) {
4851
if (enabled === undefined) {
4952
enabled = () => true
5053
}
5154
if (scrollBottomReached === undefined) {
52-
scrollBottomReached = () => {}
55+
scrollBottomReached = () => { }
5356
}
5457

5558
// Sanity checks
@@ -59,8 +62,8 @@ export default class Tab {
5962
if (typeof name !== 'string' || name.trim() === '') {
6063
throw new Error('The name argument is not a valid string')
6164
}
62-
if (typeof icon !== 'string' || icon.trim() === '') {
63-
throw new Error('The icon argument is not a valid string')
65+
if ((typeof icon !== 'string' || icon.trim() === '') && typeof iconSvg !== 'string') {
66+
throw new Error('Missing valid string for icon or iconSvg argument')
6467
}
6568
if (typeof mount !== 'function') {
6669
throw new Error('The mount argument should be a function')
@@ -87,6 +90,13 @@ export default class Tab {
8790
this._enabled = enabled
8891
this._scrollBottomReached = scrollBottomReached
8992

93+
if (typeof iconSvg === 'string') {
94+
sanitizeSVG(iconSvg)
95+
.then(sanitizedSvg => {
96+
this._iconSvgSanitized = sanitizedSvg
97+
})
98+
}
99+
90100
}
91101

92102
get id() {
@@ -101,6 +111,10 @@ export default class Tab {
101111
return this._icon
102112
}
103113

114+
get iconSvg() {
115+
return this._iconSvgSanitized
116+
}
117+
104118
get mount() {
105119
return this._mount
106120
}

apps/files/src/views/Sidebar.vue

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,12 @@
7272
:on-update="tab.update"
7373
:on-destroy="tab.destroy"
7474
:on-scroll-bottom-reached="tab.scrollBottomReached"
75-
:file-info="fileInfo" />
75+
:file-info="fileInfo">
76+
<template v-if="tab.iconSvg !== undefined" #icon>
77+
<!-- eslint-disable-next-line vue/no-v-html -->
78+
<span class="svg-icon" v-html="tab.iconSvg" />
79+
</template>
80+
</SidebarTab>
7681
</template>
7782
</NcAppSidebar>
7883
</template>
@@ -508,5 +513,13 @@ export default {
508513
top: 0 !important;
509514
height: 100% !important;
510515
}
516+
517+
.svg-icon {
518+
::v-deep svg {
519+
width: 20px;
520+
height: 20px;
521+
fill: currentColor;
522+
}
523+
}
511524
}
512525
</style>

apps/files_sharing/src/files_sharing_tab.js

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,14 @@ import Vue from 'vue'
2525
import VueClipboard from 'vue-clipboard2'
2626
import { translate as t, translatePlural as n } from '@nextcloud/l10n'
2727

28-
import SharingTab from './views/SharingTab'
29-
import ShareSearch from './services/ShareSearch'
30-
import ExternalLinkActions from './services/ExternalLinkActions'
31-
import ExternalShareActions from './services/ExternalShareActions'
32-
import TabSections from './services/TabSections'
28+
import SharingTab from './views/SharingTab.vue'
29+
import ShareSearch from './services/ShareSearch.js'
30+
import ExternalLinkActions from './services/ExternalLinkActions.js'
31+
import ExternalShareActions from './services/ExternalShareActions.js'
32+
import TabSections from './services/TabSections.js'
33+
34+
// eslint-disable-next-line node/no-missing-import, import/no-unresolved
35+
import ShareVariant from '@mdi/svg/svg/share-variant.svg?raw'
3336

3437
// Init Sharing Tab Service
3538
if (!window.OCA.Sharing) {
@@ -53,7 +56,7 @@ window.addEventListener('DOMContentLoaded', function() {
5356
OCA.Files.Sidebar.registerTab(new OCA.Files.Sidebar.Tab({
5457
id: 'sharing',
5558
name: t('files_sharing', 'Sharing'),
56-
icon: 'icon-share',
59+
iconSvg: ShareVariant,
5760

5861
async mount(el, fileInfo, context) {
5962
if (TabInstance) {

apps/files_versions/src/css/versions.css

Lines changed: 0 additions & 74 deletions
This file was deleted.
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
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+
*/
19+
20+
import Vue from 'vue'
21+
import { translate as t, translatePlural as n } from '@nextcloud/l10n'
22+
23+
import VersionTab from './views/VersionTab.vue'
24+
import VTooltip from 'v-tooltip'
25+
// eslint-disable-next-line node/no-missing-import, import/no-unresolved
26+
import BackupRestore from '@mdi/svg/svg/backup-restore.svg?raw'
27+
28+
Vue.prototype.t = t
29+
Vue.prototype.n = n
30+
31+
Vue.use(VTooltip)
32+
33+
// Init Sharing tab component
34+
const View = Vue.extend(VersionTab)
35+
let TabInstance = null
36+
37+
window.addEventListener('DOMContentLoaded', function() {
38+
if (OCA.Files?.Sidebar === undefined) {
39+
return
40+
}
41+
42+
OCA.Files.Sidebar.registerTab(new OCA.Files.Sidebar.Tab({
43+
id: 'version_vue',
44+
name: t('files_versions', 'Version'),
45+
iconSvg: BackupRestore,
46+
47+
async mount(el, fileInfo, context) {
48+
if (TabInstance) {
49+
TabInstance.$destroy()
50+
}
51+
TabInstance = new View({
52+
// Better integration with vue parent component
53+
parent: context,
54+
})
55+
// Only mount after we have all the info we need
56+
await TabInstance.update(fileInfo)
57+
TabInstance.$mount(el)
58+
},
59+
update(fileInfo) {
60+
TabInstance.update(fileInfo)
61+
},
62+
destroy() {
63+
TabInstance.$destroy()
64+
TabInstance = null
65+
},
66+
enabled(fileInfo) {
67+
return !(fileInfo?.isDirectory() ?? true)
68+
},
69+
}))
70+
})

apps/files_versions/src/templates/item.handlebars

Lines changed: 0 additions & 22 deletions
This file was deleted.

apps/files_versions/src/templates/template.handlebars

Lines changed: 0 additions & 10 deletions
This file was deleted.
Lines changed: 12 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
/**
2-
* Copyright (c) 2015
2+
* @copyright 2022 Louis Chemineau <mlouis@chmn.me>
33
*
4-
* @author John Molakvoæ <skjnldsv@protonmail.com>
5-
* @author Vincent Petry <vincent@nextcloud.com>
4+
* @author Louis Chemineau <mlouis@chmn.me>
65
*
76
* @license AGPL-3.0-or-later
87
*
@@ -18,29 +17,18 @@
1817
*
1918
* You should have received a copy of the GNU Affero General Public License
2019
* along with this program. If not, see <http://www.gnu.org/licenses/>.
21-
*
2220
*/
2321

24-
(function() {
25-
OCA.Versions = OCA.Versions || {}
22+
import { createClient, getPatcher } from 'webdav'
23+
import { generateRemoteUrl } from '@nextcloud/router'
24+
import axios from '@nextcloud/axios'
2625

27-
/**
28-
* @namespace
29-
*/
30-
OCA.Versions.Util = {
31-
/**
32-
* Initialize the versions plugin.
33-
*
34-
* @param {OCA.Files.FileList} fileList file list to be extended
35-
*/
36-
attach(fileList) {
37-
if (fileList.id === 'trashbin' || fileList.id === 'files.public') {
38-
return
39-
}
26+
const rootPath = 'dav'
4027

41-
fileList.registerTabView(new OCA.Versions.VersionsTabView('versionsTabView', { order: -10 }))
42-
},
43-
}
44-
})()
28+
// force our axios
29+
const patcher = getPatcher()
30+
patcher.patch('request', axios)
4531

46-
OC.Plugins.register('OCA.Files.FileList', OCA.Versions.Util)
32+
// init webdav client on default dav endpoint
33+
const remote = generateRemoteUrl(rootPath)
34+
export default createClient(remote)

0 commit comments

Comments
 (0)