diff --git a/frontend/src/stores/main.ts b/frontend/src/stores/main.ts new file mode 100644 index 0000000..158a5fd --- /dev/null +++ b/frontend/src/stores/main.ts @@ -0,0 +1,126 @@ +import type { FileEntry, FUID, SelectedItems } from '@/repositories/Document' +import { Doc } from '@/repositories/Document' +import { defineStore } from 'pinia' +import { collator } from '@/utils' +import { logoutUser } from '@/repositories/User' +import { watchConnect } from '@/repositories/WS' +import { shallowRef } from 'vue' + +type User = { + username: string + privileged: boolean + isOpenLoginModal: boolean + isLoggedIn: boolean +} + +export const useMainStore = defineStore({ + id: 'main', + state: () => ({ + document: shallowRef([]), + selected: new Set(), + fileExplorer: null as any, + error: '' as string, + connected: false, + server: {} as Record, + user: { + username: '', + privileged: false, + isLoggedIn: false, + isOpenLoginModal: false + } as User + }), + actions: { + updateRoot(root: FileEntry[]) { + const docs = [] + let loc = [] as string[] + for (const [level, name, key, mtime, size, isfile] of root) { + loc = loc.slice(0, level - 1) + docs.push(new Doc({ + name, + loc: level ? loc.join('/') : '/', + key, + size, + mtime, + dir: !isfile, + })) + loc.push(name) + } + this.document = docs + }, + login(username: string, privileged: boolean) { + this.user.username = username + this.user.privileged = privileged + this.user.isLoggedIn = true + this.user.isOpenLoginModal = false + if (!this.connected) watchConnect() + }, + loginDialog() { + this.user.isOpenLoginModal = true + }, + async logout() { + console.log("Logout") + await logoutUser() + this.$reset() + localStorage.clear() + history.go() // Reload page + } + }, + getters: { + isUserLogged(): boolean { + return this.user.isLoggedIn + }, + recentDocuments(): Doc[] { + const ret = [...this.document] + ret.sort((a, b) => b.mtime - a.mtime) + return ret + }, + largeDocuments(): Doc[] { + const ret = [...this.document] + ret.sort((a, b) => b.size - a.size) + return ret + }, + selectedFiles(): SelectedItems { + const selected = this.selected + const found = new Set() + const ret: SelectedItems = { + missing: new Set(), + docs: {}, + keys: [], + recursive: [], + } + for (const doc of this.document) { + if (selected.has(doc.key)) { + found.add(doc.key) + ret.keys.push(doc.key) + ret.docs[doc.key] = doc + } + } + // What did we not select? + for (const key of selected) if (!found.has(key)) ret.missing.add(key) + // Build a flat list including contents recursively + const relnames = new Set() + function add(rel: string, full: string, doc: Doc) { + if (!doc.dir && relnames.has(rel)) throw Error(`Multiple selections conflict for: ${rel}`) + relnames.add(rel) + ret.recursive.push([rel, full, doc]) + } + for (const key of ret.keys) { + const base = ret.docs[key] + const basepath = base.loc ? `${base.loc}/${base.name}` : base.name + const nremove = base.loc.length + add(base.name, basepath, base) + for (const doc of this.document) { + if (doc.loc === basepath || doc.loc.startsWith(basepath) && doc.loc[basepath.length] === '/') { + const full = doc.loc ? `${doc.loc}/${doc.name}` : doc.name + const rel = full.slice(nremove) + add(rel, full, doc) + } + } + } + // Sort by rel (name stored as on download) + ret.recursive.sort((a, b) => collator.compare(a[0], b[0])) + + return ret + } + } +})