Rewrite document store to keep all docs: filter and path selection without recreation. Much faster sorting and filtering.

This commit is contained in:
Leo Vasanko
2023-11-06 21:50:29 +00:00
parent 6938740b0f
commit e3af21af91
8 changed files with 84 additions and 131 deletions

View File

@@ -6,10 +6,9 @@ import type {
DirList,
SelectedItems
} from '@/repositories/Document'
import { formatSize, formatUnixDate } from '@/utils'
import { needleFormat, formatSize, formatUnixDate, haystackFormat, localeIncludes } from '@/utils'
import { defineStore } from 'pinia'
// @ts-ignore
import { localeIncludes } from 'locale-includes'
import { collator } from '@/utils'
type FileData = { id: string; mtime: number; size: number; dir: DirectoryData }
type DirectoryData = {
@@ -25,6 +24,7 @@ type User = {
export type DocumentStore = {
root: DirEntry
document: Document[]
search: string
selected: Set<FUID>
uploadingDocuments: Array<{ key: number; name: string; progress: number }>
uploadCount: number
@@ -40,6 +40,7 @@ export const useDocumentStore = defineStore({
state: (): DocumentStore => ({
root: {} as DirEntry,
document: [] as Document[],
search: "" as string,
selected: new Set<FUID>(),
uploadingDocuments: [],
uploadCount: 0 as number,
@@ -56,89 +57,46 @@ export const useDocumentStore = defineStore({
}),
actions: {
updateTable(matched: DirList) {
// Transform data
const dataMapped = []
for (const [name, attr] of Object.entries(matched)) {
const { key, size, mtime } = attr
const element: Document = {
name,
key,
size,
sizedisp: formatSize(size),
mtime,
modified: formatUnixDate(mtime),
type: 'dir' in attr ? 'folder' : 'file'
updateRoot(root: DirEntry | null = null) {
root ??= this.root
// Transform tree data to flat documents array
let loc = [] as Array<string>
const mapper = ([name, attr]: [string, FileEntry | DirEntry]) => ({
loc,
name,
type: 'dir' in attr ? 'folder' : 'file' as 'folder' | 'file',
...attr,
sizedisp: formatSize(attr.size),
modified: formatUnixDate(attr.mtime),
haystack: haystackFormat(name),
})
const queue = [...Object.entries(root.dir).map(mapper)]
const docs = []
for (let doc; (doc = queue.shift()) !== undefined;) {
docs.push(doc)
if ("dir" in doc) {
loc = [...doc.loc, doc.name]
queue.push(...Object.entries(doc.dir).map(mapper))
}
dataMapped.push(element)
}
// Pre sort directory entries folders first then files, names in natural ordering
dataMapped.sort((a, b) =>
a.type === b.type
? a.name.localeCompare(b.name, undefined, {
numeric: true,
sensitivity: 'base'
})
: a.type === 'folder'
? -1
: 1
docs.sort((a, b) =>
// @ts-ignore
(a.type === "file") - (b.type === "file") ||
collator.compare(a.name, b.name)
)
this.document = dataMapped
this.root = root
this.document = docs
},
setFilter(filter: string) {
if (filter === '') return this.updateTable({})
function traverseDir(data: DirEntry | FileEntry, path: string) {
if (!('dir' in data)) return
for (const [name, attr] of Object.entries(data.dir)) {
const fullname = `${path}/${name}`
if (
localeIncludes(name, filter, {
usage: 'search',
numeric: true,
sensitivity: 'base'
})
) {
matched[fullname.slice(1)] = attr // No initial slash on name
if (!--count) throw Error('Too many matches')
}
traverseDir(attr, fullname)
}
}
let count = 100
const matched: any = {}
try {
traverseDir(this.root, '')
} catch (error: any) {
if (error.message !== 'Too many matches') throw error
}
this.updateTable(matched)
find(query: string): Document[] {
const needle = needleFormat(query)
return this.document.filter(doc => localeIncludes(doc.haystack, needle))
},
setActualDocument(location: string) {
location = decodeURIComponent(location)
let data: FileEntry | DirEntry = this.root
const actualDirArr = []
try {
// Navigate to target folder
for (const dirname of location.split('/').slice(1)) {
if (!dirname) continue
if (!('dir' in data)) throw Error('Target folder not available')
actualDirArr.push(dirname)
data = data.dir[dirname]
}
} catch (error) {
console.error(
'Cannot show requested folder',
location,
actualDirArr.join('/'),
error
)
}
if (!('dir' in data)) {
// Target folder not available
this.document = []
return
}
this.updateTable(data.dir)
directory(loc: string[]) {
const ret = this.document.filter(
doc => doc.loc.length === loc.length && doc.loc.every((e, i) => e === loc[i])
)
return ret
},
updateUploadingDocuments(key: number, progress: number) {
for (const d of this.uploadingDocuments) {