diff --git a/frontend/src/components/DownloadButton.vue b/frontend/src/components/DownloadButton.vue
new file mode 100644
index 0000000..f3d5565
--- /dev/null
+++ b/frontend/src/components/DownloadButton.vue
@@ -0,0 +1,171 @@
+
+
+
+
+
+
+
+
diff --git a/frontend/src/components/HeaderSelected.vue b/frontend/src/components/HeaderSelected.vue
index 998c71d..acab35b 100644
--- a/frontend/src/components/HeaderSelected.vue
+++ b/frontend/src/components/HeaderSelected.vue
@@ -2,7 +2,7 @@
{{ store.selected.size }} selected ➤
-
+
@@ -14,7 +14,6 @@
import {connect, controlUrl} from '@/repositories/WS'
import { useMainStore } from '@/stores/main'
import { computed } from 'vue'
-import type { SelectedItems } from '@/repositories/Document'
const store = useMainStore()
const props = defineProps({
@@ -53,95 +52,6 @@ const op = (op: string, dst?: string) => {
}
}
-const linkdl = (href: string) => {
- const a = document.createElement('a')
- a.href = href
- a.download = ''
- a.click()
-}
-
-const filesystemdl = async (sel: SelectedItems, handle: FileSystemDirectoryHandle) => {
- let hdir = ''
- let h = handle
- console.log('Downloading to filesystem', sel.recursive)
- for (const [rel, full, doc] of sel.recursive) {
- // Create any missing directories
- if (hdir && !rel.startsWith(hdir + '/')) {
- hdir = ''
- h = handle
- }
- const r = rel.slice(hdir.length)
- for (const dir of r.split('/').slice(0, doc.dir ? undefined : -1)) {
- hdir += `${dir}/`
- try {
- h = await h.getDirectoryHandle(dir.normalize('NFC'), { create: true })
- } catch (error) {
- console.error('Failed to create directory', hdir, error)
- return
- }
- console.log('Created', hdir)
- }
- if (doc.dir) continue // Target was a folder and was created
- const name = rel.split('/').pop()!.normalize('NFC')
- // Download file
- let fileHandle
- try {
- fileHandle = await h.getFileHandle(name, { create: true })
- } catch (error) {
- console.error('Failed to create file', rel, full, hdir + name, error)
- return
- }
- const writable = await fileHandle.createWritable()
- const url = `/files/${rel}`
- console.log('Fetching', url)
- const res = await fetch(url)
- if (!res.ok)
- throw new Error(`Failed to download ${url}: ${res.status} ${res.statusText}`)
- if (res.body) await res.body.pipeTo(writable)
- else {
- // Zero-sized files don't have a body, so we need to create an empty file
- await writable.truncate(0)
- await writable.close()
- }
- console.log('Saved', hdir + name)
- }
-}
-
-const download = async () => {
- const sel = store.selectedFiles
- console.log('Download', sel)
- if (sel.keys.length === 0) {
- console.warn('Attempted download but no files found. Missing selected keys:', sel.missing)
- store.selected.clear()
- return
- }
- // Plain old a href download if only one file (ignoring any folders)
- const files = sel.recursive.filter(([rel, full, doc]) => !doc.dir)
- if (files.length === 1) {
- store.selected.clear()
- return linkdl(`/files/${files[0][1]}`)
- }
- // Use FileSystem API if multiple files and the browser supports it
- if ('showDirectoryPicker' in window) {
- try {
- // @ts-ignore
- const handle = await window.showDirectoryPicker({
- startIn: 'downloads',
- mode: 'readwrite'
- })
- filesystemdl(sel, handle).then(() => {
- store.selected.clear()
- })
- return
- } catch (e) {
- console.error('Download to folder aborted', e)
- }
- }
- // Otherwise, zip and download
- const name = sel.keys.length === 1 ? sel.docs[sel.keys[0]].name : 'download'
- linkdl(`/zip/${Array.from(sel.keys).join('+')}/${name}.zip`)
- store.selected.clear()
-}
diff --git a/frontend/src/components/UploadButton.vue b/frontend/src/components/UploadButton.vue
index 2bc9efa..60ac0f7 100644
--- a/frontend/src/components/UploadButton.vue
+++ b/frontend/src/components/UploadButton.vue
@@ -2,7 +2,7 @@
import { connect, uploadUrl } from '@/repositories/WS';
import { useMainStore } from '@/stores/main'
import { collator } from '@/utils';
-import { computed, onMounted, onUnmounted, reactive, ref } from 'vue'
+import { onMounted, onUnmounted, reactive, ref } from 'vue'
const fileInput = ref()
const folderInput = ref()
@@ -94,7 +94,7 @@ const cancelUploads = () => {
const uprogress_init = {
total: 0,
- uploaded: 0,
+ xfer: 0,
t0: 0,
tlast: 0,
statbytes: 0,
@@ -109,15 +109,6 @@ const uprogress_init = {
status: 'idle',
}
const uprogress = reactive({...uprogress_init})
-const percent = computed(() => uprogress.uploaded / uprogress.total * 100)
-const speed = computed(() => {
- let s = uprogress.statbytes / uprogress.statdur / 1e3
- const tsince = (Date.now() - uprogress.tlast) / 1e3
- if (tsince > 5 / s) return 0 // Less than fifth of previous speed => stalled
- if (tsince > 1 / s) return 1 / tsince // Next block is late or not coming, decay
- return s // "Current speed"
-})
-const speeddisp = computed(() => speed.value ? speed.value.toFixed(speed.value < 10 ? 1 : 0) + '\u202FMB/s': 'stalled')
setInterval(() => {
if (Date.now() - uprogress.tlast > 3000) {
// Reset
@@ -132,7 +123,7 @@ setInterval(() => {
const statUpdate = ({name, size, start, end}: {name: string, size: number, start: number, end: number}) => {
if (name !== uprogress.filename) return // If stats have been reset
const now = Date.now()
- uprogress.uploaded = uprogress.filestart + end
+ uprogress.xfer = uprogress.filestart + end
uprogress.filepos = end
uprogress.statbytes += end - start
uprogress.statdur += now - uprogress.tlast
@@ -249,57 +240,5 @@ onUnmounted(() => {
-
-
-
- [{{ uprogress.fileidx }}/{{ uprogress.filecount }}]
-
- {{ uprogress.filename.split('/').pop() }}
-
- {{ (uprogress.filepos / uprogress.filesize * 100).toFixed(0) + '\u202F%' }}
-
-
-
- {{ (uprogress.uploaded / 1e6).toFixed(0) + '\u202F/\u202F' + (uprogress.total / 1e6).toFixed(0) + '\u202FMB' }}
-
- {{ speeddisp }}
-
-
-
+
-
-
-@/stores/main