mirror of
https://github.com/nextcloud/server.git
synced 2026-06-10 17:23:59 -04:00
Merge pull request #40958 from nextcloud/pulsejet/files-list-perf
This commit is contained in:
commit
4d5b794acc
8 changed files with 42 additions and 54 deletions
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
4
dist/files-main.js
vendored
File diff suppressed because one or more lines are too long
2
dist/files-main.js.map
vendored
2
dist/files-main.js.map
vendored
File diff suppressed because one or more lines are too long
Loading…
Reference in a new issue