diff --git a/frontend/src/components/EmptyFolder.vue b/frontend/src/components/EmptyFolder.vue index 223c315..db8fe78 100644 --- a/frontend/src/components/EmptyFolder.vue +++ b/frontend/src/components/EmptyFolder.vue @@ -3,7 +3,7 @@

Access Denied

No Connection

-

Waiting for File List

+

Waiting for File List

No matches!

Folder not found

Empty folder

diff --git a/frontend/src/components/FileExplorer.vue b/frontend/src/components/FileExplorer.vue index 83e9aac..ea1b5e0 100644 --- a/frontend/src/components/FileExplorer.vue +++ b/frontend/src/components/FileExplorer.vue @@ -251,8 +251,7 @@ const mkdir = (doc: Doc, name: string) => { }) doc.name = name doc.key = crypto.randomUUID() - doc.ghost = true - store.document.push(doc) + store.addGhost(doc) editing.value = null } const showFolderBreadcrumb = (i: number) => { @@ -351,13 +350,13 @@ const copyImage = async (doc: Doc) => { const deleteFile = (doc: Doc) => { const path = doc.loc ? `${doc.loc}/${doc.name}` : doc.name - doc.ghost = true + store.hideDoc(path) const control = connect(controlUrl, { message(ev: MessageEvent) { const res = JSON.parse(ev.data) if ('error' in res) { console.error('Delete failed', res.error) - doc.ghost = false + store.unhideDoc(path) store.showToast(res.error.message || 'Delete failed') } else if (res.status === 'ack') { store.showToast(`🗑️ Deleted ${doc.name}`) diff --git a/frontend/src/components/Gallery.vue b/frontend/src/components/Gallery.vue index 27f32b3..3caf27b 100644 --- a/frontend/src/components/Gallery.vue +++ b/frontend/src/components/Gallery.vue @@ -205,8 +205,7 @@ const mkdir = (doc: Doc, name: string) => { }) doc.name = name doc.key = crypto.randomUUID() - doc.ghost = true - store.document.push(doc) + store.addGhost(doc) editing.value = null } const showFolderBreadcrumb = (i: number) => { @@ -295,13 +294,13 @@ const copyImage = async (doc: Doc) => { const deleteFile = (doc: Doc) => { const path = doc.loc ? `${doc.loc}/${doc.name}` : doc.name - doc.ghost = true + store.hideDoc(path) const control = connect(controlUrl, { message(ev: MessageEvent) { const res = JSON.parse(ev.data) if ('error' in res) { console.error('Delete failed', res.error) - doc.ghost = false + store.unhideDoc(path) store.showToast(res.error.message || 'Delete failed') } else if (res.status === 'ack') { store.showToast(`🗑️ Deleted ${doc.name}`) diff --git a/frontend/src/components/HeaderSelected.vue b/frontend/src/components/HeaderSelected.vue index 8eb5b92..d37c15e 100644 --- a/frontend/src/components/HeaderSelected.vue +++ b/frontend/src/components/HeaderSelected.vue @@ -31,23 +31,30 @@ const props = defineProps({ const dst = computed(() => props.path!.join('/')) const op = (opName: string, dst?: string) => { const sel = store.selectedFiles + const paths = sel.keys.map(key => { + const doc = sel.docs[key]! + return doc.loc ? `${doc.loc}/${doc.name}` : doc.name + }) const msg = { op: opName, - sel: sel.keys.map(key => { - const doc = sel.docs[key]! - return doc.loc ? `${doc.loc}/${doc.name}` : doc.name - }) + sel: paths } // @ts-ignore if (dst !== undefined) msg.dst = dst - if (opName === 'rm' || opName === 'mv') - for (const key of sel.keys) sel.docs[key]!.ghost = true + // Hide items being deleted or moved (optimistic update) + if (opName === 'rm' || opName === 'mv') { + for (const path of paths) store.hideDoc(path) + } const control = connect(controlUrl, { message(ev: MessageEvent) { const res = JSON.parse(ev.data) if ('error' in res) { console.error('Control socket error', msg, res.error) store.error = res.error.message + // Restore hidden items on error + if (opName === 'rm' || opName === 'mv') { + for (const path of paths) store.unhideDoc(path) + } return } else if (res.status === 'ack') { console.log('Control ack OK', res) diff --git a/frontend/src/components/UploadButton.vue b/frontend/src/components/UploadButton.vue index 645a6d6..6deb4ab 100644 --- a/frontend/src/components/UploadButton.vue +++ b/frontend/src/components/UploadButton.vue @@ -10,6 +10,7 @@