Refactor MongoDB client imports and implement lazy loading for main items in UI

This commit is contained in:
2026-04-12 17:36:49 +02:00
parent c078de0076
commit 0f372f5056
7 changed files with 151 additions and 25 deletions
+66 -11
View File
@@ -725,9 +725,14 @@
let allItems = [];
const MAIN_ITEMS_PAGE_SIZE = 120;
let mainItemsNextOffset = 0;
let mainItemsHasMore = false;
let mainItemsLoadingMore = false;
let mainItemsObserver = null;
let mainItemsSentinel = null;
function loadItems(offset = 0, append = false) {
fetch(`{{ url_for('get_items') }}?offset=${offset}&limit=${MAIN_ITEMS_PAGE_SIZE}`)
return fetch(`{{ url_for('get_items') }}?offset=${offset}&limit=${MAIN_ITEMS_PAGE_SIZE}`)
.then(response => response.json())
.then(data => {
const itemsContainer = document.querySelector('#items-container');
@@ -1009,7 +1014,7 @@
populateFilterOptions('filter2-options', [...filter2Values].sort(), 2);
populateFilterOptions('filter3-options', [...filter3Values].sort(), 3);
// Start display from leftmost position (first card, which is now Z)
// Start display from leftmost position on full reload only.
if (!append) {
itemsContainer.scrollLeft = 0;
}
@@ -1028,15 +1033,9 @@
rebuildFilter3Options();
}
if (data.has_more) {
const nextOffset = (data.offset || offset) + (data.count || pageItems.length);
const continueLoad = () => loadItems(nextOffset, true);
if ('requestIdleCallback' in window) {
requestIdleCallback(continueLoad, { timeout: 250 });
} else {
setTimeout(continueLoad, 0);
}
}
mainItemsNextOffset = (data.offset || offset) + (data.count || pageItems.length);
mainItemsHasMore = Boolean(data.has_more);
setupMainItemsLazyLoading();
})
.catch(error => {
console.error('Error fetching items:', error);
@@ -1049,6 +1048,62 @@
});
}
function ensureMainItemsSentinel() {
const itemsContainer = document.querySelector('#items-container');
if (!itemsContainer) return null;
if (!mainItemsSentinel) {
mainItemsSentinel = document.createElement('div');
mainItemsSentinel.id = 'main-items-sentinel';
mainItemsSentinel.style.flex = '0 0 1px';
mainItemsSentinel.style.width = '1px';
mainItemsSentinel.style.minWidth = '1px';
mainItemsSentinel.style.height = '1px';
mainItemsSentinel.style.pointerEvents = 'none';
}
if (!mainItemsSentinel.parentNode) {
itemsContainer.appendChild(mainItemsSentinel);
} else {
itemsContainer.appendChild(mainItemsSentinel);
}
return itemsContainer;
}
function setupMainItemsLazyLoading() {
const itemsContainer = ensureMainItemsSentinel();
if (!itemsContainer) return;
if (mainItemsObserver) {
mainItemsObserver.disconnect();
mainItemsObserver = null;
}
if (!mainItemsHasMore) return;
mainItemsObserver = new IntersectionObserver(entries => {
if (!entries.some(entry => entry.isIntersecting)) {
return;
}
if (mainItemsLoadingMore || !mainItemsHasMore) {
return;
}
mainItemsLoadingMore = true;
loadItems(mainItemsNextOffset, true).finally(() => {
mainItemsLoadingMore = false;
});
}, {
root: itemsContainer,
threshold: 0.15,
rootMargin: '0px 220px 0px 0px'
});
mainItemsObserver.observe(mainItemsSentinel);
}
function searchByCode() {
const searchInput = document.getElementById('code-search');
const rawSearchTerm = searchInput.value;