33 SPDX-License-Identifier: AGPL-3.0-or-later
44-->
55<template >
6- <div class =" log-table" >
6+ <div ref = " table " class =" log-table" @scroll = " debouncedHandleScrollPosition " >
77 <LogDetailsModal v-if =" currentRow"
88 :open.sync =" isModalOpen"
99 :current-entry.sync =" currentRow"
3535 </td >
3636 </tr >
3737
38- <LogTableRow v-for =" row, rowNumber in sortedRows"
39- :key =" rowNumber"
40- :row =" row"
41- @show-details =" showDetailsForRow" />
38+ <template v-for =" (row , rowNumber ) in sortedRows " >
39+ <tr v-if =" row.showDummy" :key =" rowNumber" class =" log-table__dummy-row" />
40+ <LogTableRow v-else
41+ :key =" rowNumber"
42+ :row =" row"
43+ @show-details =" showDetailsForRow" />
44+ </template >
4245 </tbody >
4346 <tfoot >
4447 <tr v-if =" sortedByTime !== 'ascending'" >
5962<script setup lang="ts">
6063import type { ILogEntry , ISortingOptions } from ' ../../interfaces'
6164
62- import { computed , nextTick , ref } from ' vue'
65+ import { computed , nextTick , ref , watch } from ' vue'
6366import { translate as t } from ' @nextcloud/l10n'
6467import { useSettingsStore } from ' ../../store/settings'
6568import { useLogStore } from ' ../../store/logging'
69+ import { debounce } from ' ../../utils/debounce'
6670
6771import IntersectionObserver from ' ../IntersectionObserver.vue'
6872import LogDetailsModal from ' ../LogDetailsModal.vue'
@@ -109,11 +113,27 @@ const showDetailsForRow = (row: ILogEntry) => {
109113 isModalOpen .value = true
110114}
111115
116+ /**
117+ * Reference to the table container, used to track current scroll position
118+ */
119+ const table = ref <HTMLElement >()
112120/**
113121 * Reference to the table body, used for keeping scroll position on loading more entries
114122 */
115123const tableBody = ref <HTMLElement >()
116124
125+ /**
126+ * Get index of the first visible row, to define visible scope around it
127+ * Rest entries should be rendered as dummy nodes, to reduce load while render
128+ */
129+ const firstVisibleRowIndex = ref (0 )
130+
131+ const handleScrollPosition = () => {
132+ firstVisibleRowIndex .value = Math .floor ((table .value ?.scrollTop ?? 0 ) / 42 )
133+ }
134+
135+ const debouncedHandleScrollPosition = debounce (handleScrollPosition , 100 )
136+
117137/**
118138 * Load older log entries and ensure that the view sticks at the previous top element
119139 */
@@ -144,7 +164,17 @@ const sortedRows = computed(() => {
144164 const order = (fn : SortLogFunction , type : string , a : ILogEntry , b : ILogEntry ) => type === ' ascending' ? fn (a , b ) : (type === ' descending' ? fn (b , a ) : 0 )
145165
146166 sorted .sort ((a , b ) => order (byLevel , sortedByLevel .value , a , b ) || order (byApp , sortedByApp .value , a , b ) || order (byTime , sortedByTime .value , a , b ))
147- return sorted
167+ return sorted .map ((row , index ) => ({
168+ ... row ,
169+ showDummy: index > firstVisibleRowIndex .value + 50 || index < firstVisibleRowIndex .value - 50 ,
170+ }))
171+ })
172+
173+ /**
174+ * Recalculate the visible scope of log entries on list update
175+ */
176+ watch (sortedRows , () => {
177+ handleScrollPosition ()
148178})
149179 </script >
150180
@@ -160,6 +190,10 @@ const sortedRows = computed(() => {
160190 table-layout : fixed ;
161191 }
162192
193+ & __dummy-row {
194+ height : 42px ;
195+ }
196+
163197 & __load-more {
164198 text-align : center ;
165199 padding-block : 4px ;
0 commit comments