Skip to content

Commit d119cb1

Browse files
authored
Merge pull request #39119 from nextcloud/artonge/backport/stable27/38905
[stable27] Reduce load of files versions preview loading
2 parents 27e86ab + 859552b commit d119cb1

13 files changed

Lines changed: 51 additions & 12 deletions

File tree

apps/files/src/models/Tab.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ export default class Tab {
2828
_icon
2929
_iconSvgSanitized
3030
_mount
31+
_setIsActive
3132
_update
3233
_destroy
3334
_enabled
@@ -42,12 +43,13 @@ export default class Tab {
4243
* @param {?string} options.icon the icon css class
4344
* @param {?string} options.iconSvg the icon in svg format
4445
* @param {Function} options.mount function to mount the tab
46+
* @param {Function} [options.setIsActive] function to forward the active state of the tab
4547
* @param {Function} options.update function to update the tab
4648
* @param {Function} options.destroy function to destroy the tab
4749
* @param {Function} [options.enabled] define conditions whether this tab is active. Must returns a boolean
4850
* @param {Function} [options.scrollBottomReached] executed when the tab is scrolled to the bottom
4951
*/
50-
constructor({ id, name, icon, iconSvg, mount, update, destroy, enabled, scrollBottomReached } = {}) {
52+
constructor({ id, name, icon, iconSvg, mount, setIsActive, update, destroy, enabled, scrollBottomReached } = {}) {
5153
if (enabled === undefined) {
5254
enabled = () => true
5355
}
@@ -68,6 +70,9 @@ export default class Tab {
6870
if (typeof mount !== 'function') {
6971
throw new Error('The mount argument should be a function')
7072
}
73+
if (setIsActive !== undefined && typeof setIsActive !== 'function') {
74+
throw new Error('The setIsActive argument should be a function')
75+
}
7176
if (typeof update !== 'function') {
7277
throw new Error('The update argument should be a function')
7378
}
@@ -85,6 +90,7 @@ export default class Tab {
8590
this._name = name
8691
this._icon = icon
8792
this._mount = mount
93+
this._setIsActive = setIsActive
8894
this._update = update
8995
this._destroy = destroy
9096
this._enabled = enabled
@@ -119,6 +125,10 @@ export default class Tab {
119125
return this._mount
120126
}
121127

128+
get setIsActive() {
129+
return this._setIsActive || (() => undefined)
130+
}
131+
122132
get update() {
123133
return this._update
124134
}

apps/files/src/views/Sidebar.vue

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,7 @@ export default {
366366
*/
367367
setActiveTab(id) {
368368
OCA.Files.Sidebar.setActiveTab(id)
369+
this.tabs.forEach(tab => tab.setIsActive(id === tab.id))
369370
},
370371
371372
/**
@@ -453,6 +454,7 @@ export default {
453454
if (this.$refs.tabs) {
454455
this.$refs.tabs.updateTabs()
455456
}
457+
this.setActiveTab(this.Sidebar.activeTab || this.tabs[0].id)
456458
})
457459
} catch (error) {
458460
this.error = t('files', 'Error while loading the file data')

apps/files_versions/lib/Sabre/Plugin.php

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727
namespace OCA\Files_Versions\Sabre;
2828

2929
use OC\AppFramework\Http\Request;
30+
use OCA\DAV\Connector\Sabre\FilesPlugin;
31+
use OCP\IPreview;
3032
use OCP\IRequest;
3133
use Sabre\DAV\Exception\NotFound;
3234
use Sabre\DAV\INode;
@@ -39,12 +41,12 @@
3941

4042
class Plugin extends ServerPlugin {
4143
private Server $server;
42-
private IRequest $request;
4344

4445
public const VERSION_LABEL = '{http://nextcloud.org/ns}version-label';
4546

4647
public function __construct(
47-
IRequest $request
48+
private IRequest $request,
49+
private IPreview $previewManager,
4850
) {
4951
$this->request = $request;
5052
}
@@ -91,6 +93,7 @@ public function afterGet(RequestInterface $request, ResponseInterface $response)
9193
public function propFind(PropFind $propFind, INode $node): void {
9294
if ($node instanceof VersionFile) {
9395
$propFind->handle(self::VERSION_LABEL, fn() => $node->getLabel());
96+
$propFind->handle(FilesPlugin::HAS_PREVIEW_PROPERTYNAME, fn () => $this->previewManager->isMimeSupported($node->getContentType()));
9497
}
9598
}
9699

apps/files_versions/lib/Sabre/VersionFile.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
use OCA\Files_Versions\Versions\INameableVersionBackend;
3232
use OCA\Files_Versions\Versions\IVersion;
3333
use OCA\Files_Versions\Versions\IVersionManager;
34+
use OCP\Files\FileInfo;
3435
use OCP\Files\NotFoundException;
3536
use Sabre\DAV\Exception\Forbidden;
3637
use Sabre\DAV\Exception\NotFound;

apps/files_versions/src/components/Version.vue

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,15 @@
2323
:force-display-actions="true"
2424
data-files-versions-version>
2525
<template #icon>
26-
<img v-if="!previewError"
26+
<div v-if="!(loadPreview || previewLoaded)" class="version__image" />
27+
<img v-else-if="isCurrent || version.hasPreview"
2728
:src="previewURL"
2829
alt=""
30+
decoding="async"
31+
fetchpriority="low"
32+
loading="lazy"
2933
class="version__image"
30-
@error="previewError = true">
34+
@load="previewLoaded = true">
3135
<div v-else
3236
class="version__image">
3337
<ImageOffOutline :size="20" />
@@ -176,13 +180,17 @@ export default {
176180
type: Boolean,
177181
default: false,
178182
},
183+
loadPreview: {
184+
type: Boolean,
185+
default: false,
186+
},
179187
},
180188
data() {
181189
return {
190+
previewLoaded: false,
182191
showVersionLabelForm: false,
183192
formVersionLabelValue: this.version.label,
184193
capabilities: loadState('core', 'capabilities', { files: { version_labeling: false, version_deletion: false } }),
185-
previewError: false,
186194
}
187195
},
188196
computed: {

apps/files_versions/src/files_versions_tab.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@ window.addEventListener('DOMContentLoaded', function() {
5959
update(fileInfo) {
6060
TabInstance.update(fileInfo)
6161
},
62+
setIsActive(isActive) {
63+
TabInstance.setIsActive(isActive)
64+
},
6265
destroy() {
6366
TabInstance.$destroy()
6467
TabInstance = null

apps/files_versions/src/utils/davRequest.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,5 +30,6 @@ export default `<?xml version="1.0"?>
3030
<d:getcontenttype />
3131
<d:getlastmodified />
3232
<nc:version-label />
33+
<nc:has-preview />
3334
</d:prop>
3435
</d:propfind>`

apps/files_versions/src/utils/versions.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import moment from '@nextcloud/moment'
3636
* @property {string} size - Human readable size
3737
* @property {string} type - 'file'
3838
* @property {number} mtime - Version creation date as a timestamp
39+
* @property {boolean} hasPreview - Whether the version has a preview
3940
* @property {string} preview - Preview URL of the version
4041
* @property {string} url - Download URL of the version
4142
* @property {string|null} fileVersion - The version id, null for the current version
@@ -98,6 +99,7 @@ function formatVersion(version, fileInfo) {
9899
size: version.size,
99100
type: version.type,
100101
mtime: moment(version.lastmod).unix() * 1000,
102+
hasPreview: version.props['has-preview'] === 1,
101103
preview: generateUrl('/apps/files_versions/preview?file={file}&version={fileVersion}', {
102104
file: joinPaths(fileInfo.path, fileInfo.name),
103105
fileVersion: version.basename,

apps/files_versions/src/views/VersionTab.vue

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
<ul data-files-versions-versions-list>
2020
<Version v-for="version in orderedVersions"
2121
:key="version.mtime"
22+
:load-preview="isActive"
2223
:version="version"
2324
:file-info="fileInfo"
2425
:is-current="version.mtime === fileInfo.mtime"
@@ -42,6 +43,7 @@ export default {
4243
data() {
4344
return {
4445
fileInfo: null,
46+
isActive: false,
4547
/** @type {import('../utils/versions.js').Version[]} */
4648
versions: [],
4749
loading: false,
@@ -89,6 +91,13 @@ export default {
8991
this.fetchVersions()
9092
},
9193
94+
/**
95+
* @param {boolean} isActive whether the tab is active
96+
*/
97+
async setIsActive(isActive) {
98+
this.isActive = isActive
99+
},
100+
92101
/**
93102
* Get the existing versions infos
94103
*/

dist/files-sidebar.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)