Prebuild lookup structures to reduce UI lag on very large file lists.

This commit is contained in:
2026-02-04 00:18:28 +00:00
parent 0bc2a12cfa
commit 1af6cd82fe
4 changed files with 21 additions and 4 deletions
+1 -1
View File
@@ -98,7 +98,7 @@ const uploadCloudFiles = (files: CloudFile[]) => {
files.sort((a, b) => collator.compare(a.cloudName, b.cloudName)) files.sort((a, b) => collator.compare(a.cloudName, b.cloudName))
// Optimistic update: ghost folders and files // Optimistic update: ghost folders and files
const now = Math.floor(Date.now() / 1000) const now = Math.floor(Date.now() / 1000)
const byPath = new Map(store.document.map(d => [d.loc ? `${d.loc}/${d.name}` : d.name, d])) const byPath = store.docsByPath
const added = new Set<string>() const added = new Set<string>()
for (const f of files) { for (const f of files) {
const lastSlash = f.cloudName.lastIndexOf('/') const lastSlash = f.cloudName.lastIndexOf('/')
+18
View File
@@ -269,6 +269,24 @@ export const useMainStore = defineStore('main', {
sortOrder(): SortOrder { return this.query ? this.prefs.sortFiltered : this.prefs.sortListing }, sortOrder(): SortOrder { return this.query ? this.prefs.sortFiltered : this.prefs.sortListing },
isUserLogged(): boolean { return this.user.isLoggedIn }, isUserLogged(): boolean { return this.user.isLoggedIn },
recentDocuments(): Doc[] { return sorted(this.document, 'modified') }, recentDocuments(): Doc[] { return sorted(this.document, 'modified') },
/** Set of all full paths - for O(1) existence checks */
pathSet(): Set<string> {
return new Set(this.document.map(d => d.loc ? `${d.loc}/${d.name}` : d.name))
},
/** Map from location to documents in that folder - for O(1) folder listing */
docsByLoc(): Map<string, Doc[]> {
const map = new Map<string, Doc[]>()
for (const doc of this.document) {
const arr = map.get(doc.loc)
if (arr) arr.push(doc)
else map.set(doc.loc, [doc])
}
return map
},
/** Map from full path to Doc - for O(1) path lookup */
docsByPath(): Map<string, Doc> {
return new Map(this.document.map(d => [d.loc ? `${d.loc}/${d.name}` : d.name, d]))
},
selectedFiles(): SelectedItems { selectedFiles(): SelectedItems {
const selected = this.selected const selected = this.selected
const found = new Set<FUID>() const found = new Set<FUID>()
+1 -2
View File
@@ -3,8 +3,7 @@ import { useMainStore } from '@/stores/main'
export const exists = (path: string[]) => { export const exists = (path: string[]) => {
const store = useMainStore() const store = useMainStore()
const p = path.join('/') return store.pathSet.has(path.join('/'))
return store.document.some(doc => (doc.loc ? `${doc.loc}/${doc.name}` : doc.name) === p)
} }
/** Strip file extension intelligently (handles .tar.gz, name.with.dots.pdf, etc.) */ /** Strip file extension intelligently (handles .tar.gz, name.with.dots.pdf, etc.) */
+1 -1
View File
@@ -51,7 +51,7 @@ const documents = computed(() => {
// List the current location (no search) // List the current location (no search)
if (!query) return sorted( if (!query) return sorted(
store.document.filter(doc => doc.loc === loc), store.docsByLoc.get(loc) ?? [],
store.prefs.sortListing, store.prefs.sortListing,
) )