Merge pull request #40958 from nextcloud/pulsejet/files-list-perf

This commit is contained in:
John Molakvoæ 2023-10-19 09:27:43 +02:00 committed by GitHub
commit 4d5b794acc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 42 additions and 54 deletions

View file

@ -21,7 +21,7 @@
-->
<template>
<tr :class="{'files-list__row--visible': visible, 'files-list__row--active': isActive, 'files-list__row--dragover': dragover, 'files-list__row--loading': isLoading}"
<tr :class="{'files-list__row--dragover': dragover, 'files-list__row--loading': isLoading}"
data-cy-files-list-row
:data-cy-files-list-row-fileid="fileid"
:data-cy-files-list-row-name="source.basename"
@ -37,8 +37,7 @@
<span v-if="source.attributes.failed" class="files-list__row--failed" />
<!-- Checkbox -->
<FileEntryCheckbox v-if="visible"
:display-name="displayName"
<FileEntryCheckbox :display-name="displayName"
:fileid="fileid"
:is-loading="isLoading"
:nodes="nodes" />
@ -67,8 +66,7 @@
:files-list-width="filesListWidth"
:loading.sync="loading"
:opened.sync="openedMenu"
:source="source"
:visible="visible" />
:source="source" />
<!-- Size -->
<td v-if="!compact && isSizeAvailable"
@ -95,8 +93,7 @@
class="files-list__row-column-custom"
:data-cy-files-list-row-column-custom="column.id"
@click="openDetailsIfAvailable">
<CustomElementRender v-if="visible"
:current-view="currentView"
<CustomElementRender :current-view="currentView"
:render="column.render"
:source="source" />
</td>
@ -146,10 +143,6 @@ export default Vue.extend({
},
props: {
visible: {
type: Boolean,
default: false,
},
isMtimeAvailable: {
type: Boolean,
default: false,

View file

@ -20,8 +20,7 @@
-
-->
<template>
<td v-show="visible"
class="files-list__row-actions"
<td class="files-list__row-actions"
data-cy-files-list-row-actions>
<!-- Render actions -->
<CustomElementRender v-for="action in enabledRenderActions"
@ -33,10 +32,9 @@
class="files-list__row-action--inline" />
<!-- Menu actions -->
<NcActions v-if="visible"
ref="actionsMenu"
:boundaries-element="getBoundariesElement()"
:container="getBoundariesElement()"
<NcActions ref="actionsMenu"
:boundaries-element="getBoundariesElement"
:container="getBoundariesElement"
:disabled="isLoading || loading !== ''"
:force-name="true"
:force-menu="enabledInlineActions.length === 0 /* forceMenu only if no inline actions */"
@ -70,6 +68,7 @@ import NcActions from '@nextcloud/vue/dist/Components/NcActions.js'
import NcIconSvgWrapper from '@nextcloud/vue/dist/Components/NcIconSvgWrapper.js'
import NcLoadingIcon from '@nextcloud/vue/dist/Components/NcLoadingIcon.js'
import CustomElementRender from '../CustomElementRender.vue'
import logger from '../../logger.js'
// The registered actions list
@ -83,6 +82,7 @@ export default Vue.extend({
NcActions,
NcIconSvgWrapper,
NcLoadingIcon,
CustomElementRender,
},
props: {
@ -102,10 +102,6 @@ export default Vue.extend({
type: Object as PropType<Node>,
required: true,
},
visible: {
type: Boolean,
default: false,
},
gridMode: {
type: Boolean,
default: false,
@ -150,7 +146,7 @@ export default Vue.extend({
// Enabled action that are displayed inline with a custom render function
enabledRenderActions() {
if (!this.visible || this.gridMode) {
if (this.gridMode) {
return []
}
return this.enabledActions.filter(action => typeof action.renderInline === 'function')
@ -182,9 +178,7 @@ export default Vue.extend({
this.$emit('update:opened', value)
},
},
},
methods: {
/**
* Making this a function in case the files-list
* reference changes in the future. That way we're
@ -193,7 +187,9 @@ export default Vue.extend({
getBoundariesElement() {
return document.querySelector('.app-content > table.files-list')
},
},
methods: {
actionDisplayName(action: FileAction) {
if (this.filesListWidth < 768 && action.inline && typeof action.title === 'function') {
// if an inline action is rendered in the menu for

View file

@ -22,9 +22,9 @@
<template>
<span class="files-list__row-icon">
<template v-if="source.type === 'folder'">
<FolderOpenIcon v-if="dragover" />
<FolderOpenIcon v-once v-if="dragover" />
<template v-else>
<FolderIcon />
<FolderIcon v-once />
<OverlayIcon :is="folderOverlay"
v-if="folderOverlay"
class="files-list__row-icon-overlay" />
@ -41,13 +41,13 @@
@error="backgroundFailed = true"
@load="backgroundFailed = false">
<FileIcon v-else />
<FileIcon v-once v-else />
<!-- Favorite icon -->
<span v-if="isFavorite"
class="files-list__row-icon-favorite"
:aria-label="t('files', 'Favorite')">
<FavoriteIcon />
<FavoriteIcon v-once />
</span>
</span>
</template>

View file

@ -21,7 +21,7 @@
-->
<template>
<tr :class="{'files-list__row--visible': visible, 'files-list__row--active': isActive, 'files-list__row--dragover': dragover, 'files-list__row--loading': isLoading}"
<tr :class="{'files-list__row--active': isActive, 'files-list__row--dragover': dragover, 'files-list__row--loading': isLoading}"
data-cy-files-list-row
:data-cy-files-list-row-fileid="fileid"
:data-cy-files-list-row-name="source.basename"
@ -37,8 +37,7 @@
<span v-if="source.attributes.failed" class="files-list__row--failed" />
<!-- Checkbox -->
<FileEntryCheckbox v-if="visible"
:display-name="displayName"
<FileEntryCheckbox :display-name="displayName"
:fileid="fileid"
:is-loading="isLoading"
:nodes="nodes" />
@ -69,8 +68,7 @@
:grid-mode="true"
:loading.sync="loading"
:opened.sync="openedMenu"
:source="source"
:visible="visible" />
:source="source" />
</tr>
</template>
@ -115,10 +113,6 @@ export default Vue.extend({
inheritAttrs: false,
props: {
visible: {
type: Boolean,
default: false,
},
source: {
type: [Folder, NcFile, Node] as PropType<Node>,
required: true,

View file

@ -259,18 +259,17 @@ export default Vue.extend({
event.preventDefault()
event.stopPropagation()
// If reaching top, scroll up
const firstVisible = this.$refs.table?.$el?.querySelector('.files-list__row--visible') as HTMLElement
const firstSibling = firstVisible?.previousElementSibling as HTMLElement
if ([firstVisible, firstSibling].some(elmt => elmt?.contains(event.target as Node))) {
const tableTop = this.$refs.table.$el.getBoundingClientRect().top
const tableBottom = tableTop + this.$refs.table.$el.getBoundingClientRect().height
// If reaching top, scroll up. Using 100 because of the floating header
if (event.clientY < tableTop + 100) {
this.$refs.table.$el.scrollTop = this.$refs.table.$el.scrollTop - 25
return
}
// If reaching bottom, scroll down
const lastVisible = [...(this.$refs.table?.$el?.querySelectorAll('.files-list__row--visible') || [])].pop() as HTMLElement
const nextSibling = lastVisible?.nextElementSibling as HTMLElement
if ([lastVisible, nextSibling].some(elmt => elmt?.contains(event.target as Node))) {
if (event.clientY > tableBottom - 50) {
this.$refs.table.$el.scrollTop = this.$refs.table.$el.scrollTop + 25
}
},
@ -312,6 +311,8 @@ export default Vue.extend({
&::v-deep {
// Table head, body and footer
tbody {
will-change: scroll-position, padding;
contain: layout paint style;
display: flex;
flex-direction: column;
width: 100%;
@ -320,6 +321,7 @@ export default Vue.extend({
/* Hover effect on tbody lines only */
tr {
contain: strict;
&:hover,
&:focus {
background-color: var(--color-background-dark);
@ -329,6 +331,7 @@ export default Vue.extend({
// Before table and thead
.files-list__before {
contain: strict;
display: flex;
flex-direction: column;
}

View file

@ -18,7 +18,6 @@
<component :is="dataComponent"
v-for="({key, item}, i) in renderedItems"
:key="key"
:visible="(i >= bufferItems - 1 || index <= bufferItems) && (i <= shownItems - bufferItems)"
:source="item"
:index="i"
v-bind="extraProps" />
@ -211,7 +210,7 @@ export default Vue.extend({
}
// Adding scroll listener AFTER the initial scroll to index
this.$el.addEventListener('scroll', this.onScroll)
this.$el.addEventListener('scroll', this.onScroll, { passive: true })
this.$_recycledPool = {} as Record<string, any>
},
@ -232,11 +231,14 @@ export default Vue.extend({
},
onScroll() {
const topScroll = this.$el.scrollTop - this.beforeHeight
const index = Math.floor(topScroll / this.itemHeight) * this.columnCount
// Max 0 to prevent negative index
this.index = Math.max(0, index)
this.$emit('scroll')
this._onScrollHandle ??= requestAnimationFrame(() => {
this._onScrollHandle = null;
const topScroll = this.$el.scrollTop - this.beforeHeight
const index = Math.floor(topScroll / this.itemHeight) * this.columnCount
// Max 0 to prevent negative index
this.index = Math.max(0, index)
this.$emit('scroll')
});
},
},
})

4
dist/files-main.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long