Refactor replacing Document type with Doc class with computed properties. Switched Doc storage to shallowRefs for extra performance and to keep the Doc class included.

This commit is contained in:
Leo Vasanko 2023-11-13 14:48:43 +00:00
parent d4e91ea9a6
commit 3d3b078e60
6 changed files with 63 additions and 61 deletions

View File

@ -79,28 +79,28 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, computed, watchEffect, onMounted, onUnmounted } from 'vue' import { ref, computed, watchEffect, shallowRef } from 'vue'
import { useDocumentStore } from '@/stores/documents' import { useDocumentStore } from '@/stores/documents'
import type { Document } from '@/repositories/Document' import { Doc } from '@/repositories/Document'
import FileRenameInput from './FileRenameInput.vue' import FileRenameInput from './FileRenameInput.vue'
import { connect, controlUrl } from '@/repositories/WS' import { connect, controlUrl } from '@/repositories/WS'
import { collator, formatSize, formatUnixDate } from '@/utils' import { collator, formatSize } from '@/utils'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
const props = defineProps<{ const props = defineProps<{
path: Array<string> path: Array<string>
documents: Document[] documents: Doc[]
}>() }>()
const documentStore = useDocumentStore() const documentStore = useDocumentStore()
const router = useRouter() const router = useRouter()
const url_for = (doc: Document) => { const url_for = (doc: Doc) => {
const p = doc.loc ? `${doc.loc}/${doc.name}` : doc.name const p = doc.loc ? `${doc.loc}/${doc.name}` : doc.name
return doc.dir ? `#/${p}/` : `/files/${p}` return doc.dir ? `#/${p}/` : `/files/${p}`
} }
const cursor = ref<Document | null>(null) const cursor = shallowRef<Doc | null>(null)
// File rename // File rename
const editing = ref<Document | null>(null) const editing = shallowRef<Doc | null>(null)
const rename = (doc: Document, newName: string) => { const rename = (doc: Doc, newName: string) => {
const oldName = doc.name const oldName = doc.name
const control = connect(controlUrl, { const control = connect(controlUrl, {
message(ev: MessageEvent) { message(ev: MessageEvent) {
@ -124,7 +124,7 @@ const rename = (doc: Document, newName: string) => {
} }
doc.name = newName // We should get an update from watch but this is quicker doc.name = newName // We should get an update from watch but this is quicker
} }
const sortedDocuments = computed(() => sorted(props.documents as Document[])) const sortedDocuments = computed(() => sorted(props.documents))
const showFolderBreadcrumb = (i: number) => { const showFolderBreadcrumb = (i: number) => {
const docs = sortedDocuments.value const docs = sortedDocuments.value
const docloc = docs[i].loc const docloc = docs[i].loc
@ -132,19 +132,15 @@ const showFolderBreadcrumb = (i: number) => {
} }
defineExpose({ defineExpose({
newFolder() { newFolder() {
const now = Date.now() / 1000 const now = Math.floor(Date.now() / 1000)
editing.value = { editing.value = new Doc({
loc: loc.value, loc: loc.value,
key: 'new', key: 'new',
name: 'New Folder', name: 'New Folder',
dir: true, dir: true,
mtime: now, mtime: now,
size: 0, size: 0,
sizedisp: formatSize(0), })
modified: formatUnixDate(now),
haystack: '',
}
console.log("New")
}, },
toggleSelectAll() { toggleSelectAll() {
console.log('Select') console.log('Select')
@ -229,14 +225,7 @@ watchEffect(() => {
focusBreadcrumb() focusBreadcrumb()
} }
}) })
// Update human-readable x seconds ago messages from mtimes const mkdir = (doc: Doc, name: string) => {
let modifiedTimer: any = null
const updateModified = () => {
for (const doc of props.documents) doc.modified = formatUnixDate(doc.mtime)
}
onMounted(() => { updateModified(); modifiedTimer = setInterval(updateModified, 1000) })
onUnmounted(() => { clearInterval(modifiedTimer) })
const mkdir = (doc: Document, name: string) => {
const control = connect(controlUrl, { const control = connect(controlUrl, {
open() { open() {
control.send( control.send(
@ -257,7 +246,9 @@ const mkdir = (doc: Document, name: string) => {
} }
} }
}) })
doc.name = name // We should get an update from watch but this is quicker // We should get an update from watch but this is quicker
doc.name = name
doc.key = crypto.randomUUID()
} }
// Column sort // Column sort
@ -266,11 +257,11 @@ const toggleSort = (name: string) => {
} }
const sort = ref<string>('') const sort = ref<string>('')
const sortCompare = { const sortCompare = {
name: (a: Document, b: Document) => collator.compare(a.name, b.name), name: (a: Doc, b: Doc) => collator.compare(a.name, b.name),
modified: (a: Document, b: Document) => b.mtime - a.mtime, modified: (a: Doc, b: Doc) => b.mtime - a.mtime,
size: (a: Document, b: Document) => b.size - a.size size: (a: Doc, b: Doc) => b.size - a.size
} }
const sorted = (documents: Document[]) => { const sorted = (documents: Doc[]) => {
const cmp = sortCompare[sort.value as keyof typeof sortCompare] const cmp = sortCompare[sort.value as keyof typeof sortCompare]
const sorted = [...documents] const sorted = [...documents]
if (cmp) sorted.sort(cmp) if (cmp) sorted.sort(cmp)
@ -280,7 +271,7 @@ const selectionIndeterminate = computed({
get: () => { get: () => {
return ( return (
props.documents.length > 0 && props.documents.length > 0 &&
props.documents.some((doc: Document) => documentStore.selected.has(doc.key)) && props.documents.some((doc: Doc) => documentStore.selected.has(doc.key)) &&
!allSelected.value !allSelected.value
) )
}, },
@ -291,7 +282,7 @@ const allSelected = computed({
get: () => { get: () => {
return ( return (
props.documents.length > 0 && props.documents.length > 0 &&
props.documents.every((doc: Document) => documentStore.selected.has(doc.key)) props.documents.every((doc: Doc) => documentStore.selected.has(doc.key))
) )
}, },
set: (value: boolean) => { set: (value: boolean) => {
@ -308,7 +299,7 @@ const allSelected = computed({
const loc = computed(() => props.path.join('/')) const loc = computed(() => props.path.join('/'))
const contextMenu = (ev: Event, doc: Document) => { const contextMenu = (ev: Event, doc: Doc) => {
cursor.value = doc cursor.value = doc
console.log('Context menu', ev, doc) console.log('Context menu', ev, doc)
} }

View File

@ -5,7 +5,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import type { Document } from '@/repositories/Document' import { Doc } from '@/repositories/Document'
import { computed } from 'vue' import { computed } from 'vue'
const datetime = computed(() => const datetime = computed(() =>
@ -17,6 +17,6 @@ const tooltip = computed(() =>
) )
const props = defineProps<{ const props = defineProps<{
doc: Document doc: Doc
}>() }>()
</script> </script>

View File

@ -12,7 +12,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import type { Document } from '@/repositories/Document' import { Doc } from '@/repositories/Document'
import { ref, onMounted, nextTick } from 'vue' import { ref, onMounted, nextTick } from 'vue'
const input = ref<HTMLInputElement | null>(null) const input = ref<HTMLInputElement | null>(null)
@ -28,8 +28,8 @@ onMounted(() => {
}) })
const props = defineProps<{ const props = defineProps<{
doc: Document doc: Doc
rename: (doc: Document, newName: string) => void rename: (doc: Doc, newName: string) => void
exit: () => void exit: () => void
}>() }>()

View File

@ -3,7 +3,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import type { Document } from '@/repositories/Document' import { Doc } from '@/repositories/Document'
import { computed } from 'vue' import { computed } from 'vue'
const sizeClass = computed(() => { const sizeClass = computed(() => {
@ -12,7 +12,7 @@ const sizeClass = computed(() => {
}) })
const props = defineProps<{ const props = defineProps<{
doc: Document doc: Doc
}>() }>()
</script> </script>

View File

@ -1,17 +1,34 @@
import { formatSize, formatUnixDate, haystackFormat } from "@/utils"
export type FUID = string export type FUID = string
export type Document = { export type DocProps = {
loc: string loc: string
name: string name: string
key: FUID key: FUID
size: number size: number
sizedisp: string
mtime: number mtime: number
modified: string
haystack: string
dir: boolean dir: boolean
} }
export class Doc {
private _name: string = ""
public loc: string = ""
public key: FUID = ""
public size: number = 0
public mtime: number = 0
public haystack: string = ""
public dir: boolean = false
constructor(props: Partial<DocProps> = {}) { Object.assign(this, props) }
get name() { return this._name }
set name(name: string) {
this._name = name
this.haystack = haystackFormat(name)
}
get sizedisp(): string { return formatSize(this.size) }
get modified(): string { return formatUnixDate(this.mtime) }
}
export type errorEvent = { export type errorEvent = {
error: { error: {
code: number code: number
@ -36,7 +53,7 @@ export type UpdateEntry = ['k', number] | ['d', number] | ['i', Array<FileEntry>
// Helper structure for selections // Helper structure for selections
export interface SelectedItems { export interface SelectedItems {
keys: FUID[] keys: FUID[]
docs: Record<FUID, Document> docs: Record<FUID, Doc>
recursive: Array<[string, string, Document]> recursive: Array<[string, string, Doc]>
missing: Set<FUID> missing: Set<FUID>
} }

View File

@ -1,14 +1,11 @@
import type { Document, FileEntry, FUID, SelectedItems } from '@/repositories/Document' import type { FileEntry, FUID, SelectedItems } from '@/repositories/Document'
import { formatSize, formatUnixDate, haystackFormat } from '@/utils' import { Doc } from '@/repositories/Document'
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
import { collator } from '@/utils' import { collator } from '@/utils'
import { logoutUser } from '@/repositories/User' import { logoutUser } from '@/repositories/User'
import { watchConnect } from '@/repositories/WS' import { watchConnect } from '@/repositories/WS'
import { shallowRef } from 'vue'
type FileData = { id: string; mtime: number; size: number; dir: DirectoryData }
type DirectoryData = {
[filename: string]: FileData
}
type User = { type User = {
username: string username: string
privileged: boolean privileged: boolean
@ -19,7 +16,7 @@ type User = {
export const useDocumentStore = defineStore({ export const useDocumentStore = defineStore({
id: 'documents', id: 'documents',
state: () => ({ state: () => ({
document: [] as Document[], document: shallowRef<Doc[]>([]),
selected: new Set<FUID>(), selected: new Set<FUID>(),
fileExplorer: null as any, fileExplorer: null as any,
error: '' as string, error: '' as string,
@ -38,20 +35,17 @@ export const useDocumentStore = defineStore({
let loc = [] as string[] let loc = [] as string[]
for (const [level, name, key, mtime, size, isfile] of root) { for (const [level, name, key, mtime, size, isfile] of root) {
loc = loc.slice(0, level - 1) loc = loc.slice(0, level - 1)
docs.push({ docs.push(new Doc({
name, name,
loc: level ? loc.join('/') : '/', loc: level ? loc.join('/') : '/',
key, key,
size, size,
sizedisp: formatSize(size),
mtime, mtime,
modified: formatUnixDate(mtime),
haystack: haystackFormat(name),
dir: !isfile, dir: !isfile,
}) }))
loc.push(name) loc.push(name)
} }
this.document = docs as Document[] this.document = docs
}, },
login(username: string, privileged: boolean) { login(username: string, privileged: boolean) {
this.user.username = username this.user.username = username
@ -75,12 +69,12 @@ export const useDocumentStore = defineStore({
isUserLogged(): boolean { isUserLogged(): boolean {
return this.user.isLoggedIn return this.user.isLoggedIn
}, },
recentDocuments(): Document[] { recentDocuments(): Doc[] {
const ret = [...this.document] const ret = [...this.document]
ret.sort((a, b) => b.mtime - a.mtime) ret.sort((a, b) => b.mtime - a.mtime)
return ret return ret
}, },
largeDocuments(): Document[] { largeDocuments(): Doc[] {
const ret = [...this.document] const ret = [...this.document]
ret.sort((a, b) => b.size - a.size) ret.sort((a, b) => b.size - a.size)
return ret return ret
@ -105,7 +99,7 @@ export const useDocumentStore = defineStore({
for (const key of selected) if (!found.has(key)) ret.missing.add(key) for (const key of selected) if (!found.has(key)) ret.missing.add(key)
// Build a flat list including contents recursively // Build a flat list including contents recursively
const relnames = new Set<string>() const relnames = new Set<string>()
function add(rel: string, full: string, doc: Document) { function add(rel: string, full: string, doc: Doc) {
if (!doc.dir && relnames.has(rel)) throw Error(`Multiple selections conflict for: ${rel}`) if (!doc.dir && relnames.has(rel)) throw Error(`Multiple selections conflict for: ${rel}`)
relnames.add(rel) relnames.add(rel)
ret.recursive.push([rel, full, doc]) ret.recursive.push([rel, full, doc])