diff --git a/core/frontend/bun.lockb b/core/frontend/bun.lockb index b295391307..66d4740e72 100755 Binary files a/core/frontend/bun.lockb and b/core/frontend/bun.lockb differ diff --git a/core/frontend/package.json b/core/frontend/package.json index 60ed95e129..083c40c7fa 100644 --- a/core/frontend/package.json +++ b/core/frontend/package.json @@ -60,6 +60,7 @@ "semver": "^7.3.8", "semver-stable": "^3.0.0", "simple-icons": "11", + "streamsaver": "^2.0.6", "three": "0.156.1", "util": "^0.12.5", "uuid": "^9.0.0", diff --git a/core/frontend/src/components/app/SettingsMenu.vue b/core/frontend/src/components/app/SettingsMenu.vue index 658a0340ff..2ca72374a9 100644 --- a/core/frontend/src/components/app/SettingsMenu.vue +++ b/core/frontend/src/components/app/SettingsMenu.vue @@ -62,6 +62,7 @@ @@ -73,7 +74,7 @@ @@ -85,24 +86,22 @@
- +
+
+ -
-
- Deleting: {{ current_deletion_path }} -
-
- Size: {{ formatSize(current_deletion_size / 1024) }} -
-
- Total: {{ formatSize(current_deletion_total_size / 1024) }} -
-
- Status: {{ current_deletion_status }} -
-
@@ -116,6 +115,7 @@ @@ -127,7 +127,7 @@ @@ -137,6 +137,18 @@ + +
+ +
+
+ @@ -175,12 +187,13 @@ diff --git a/core/frontend/src/libs/filebrowser.ts b/core/frontend/src/libs/filebrowser.ts index c5ed140bef..072b117100 100644 --- a/core/frontend/src/libs/filebrowser.ts +++ b/core/frontend/src/libs/filebrowser.ts @@ -2,6 +2,7 @@ import Notifier from '@/libs/notifier' import { FilebrowserCredentials, FilebrowserFile, FilebrowserFolder } from '@/types/filebrowser' import { filebrowser_service } from '@/types/frontend_services' import back_axios from '@/utils/api' +import streamSaver from 'streamsaver' const notifier = new Notifier(filebrowser_service) @@ -168,10 +169,43 @@ class Filebrowser { /* Download folder */ /** * @param folder - FilebrowserFolder + * @param progressHandler - The progress handler for the download * */ - async downloadFolder(folder: FilebrowserFolder): Promise { + async downloadFolder( + folder: FilebrowserFolder, + progressHandler: (event: any) => void, + ): Promise { const url = `${filebrowser_url}/raw/${folder.path}/?algo=zip&auth=${await this.filebrowserToken()}` - window.open(url) + + const response = await fetch(url, { + headers: { Authorization: `Bearer ${await this.filebrowserToken()}` }, + }) + if (!response.ok || !response.body) throw new Error('Failed to download folder'); + + const contentLength = Number(response.headers.get('content-length') ?? 0) + const fileStream = streamSaver.createWriteStream(`${folder.name}.zip`, { + size: contentLength || undefined, + }) + const writer = fileStream.getWriter() + const reader = response.body.getReader() + + let downloaded = 0 + try { + while (true) { + const { done, value } = await reader.read() + if (done) break + downloaded += value.length + progressHandler({ bytes: value.byteLength, loaded: downloaded, total: contentLength }) + await writer.write(value) + } + + await writer.close() + notifier.pushSuccess('DOWNLOAD_COMPLETE', `Folder ${folder.path} downloaded successfully`) + } catch (err) { + await writer.abort(err) + notifier.pushError('DOWNLOAD_FAIL', `Could not download folder ${folder.path}`) + throw err + } } } diff --git a/core/frontend/src/utils/folder_manager.ts b/core/frontend/src/utils/folder_manager.ts new file mode 100644 index 0000000000..eefa061417 --- /dev/null +++ b/core/frontend/src/utils/folder_manager.ts @@ -0,0 +1,38 @@ +import filebrowser from "@/libs/filebrowser"; + +export class FolderManager { + public downloadedBytes: number = 0; + public totalBytes: number = 0; + public startTime: number = 0; + public downloadSpeed: number = 0; + + public inProgress: boolean = false; + + async downloadFolder( + logs: string, + ): Promise { + const folder = await filebrowser.fetchFolder(logs); + this.inProgress = true; + await filebrowser.downloadFolder(folder, (event) => { + if (this.startTime === 0) this.startTime = Date.now() + const current_time = Date.now() + const elapsed = (current_time - this.startTime) / 1000 + this.startTime = current_time + + this.downloadedBytes = event.bytes + this.totalBytes = event.loaded + this.downloadSpeed = event.bytes / elapsed + }) + .finally(() => { + this.resetDownloadVariables() + this.inProgress = false; + }) + } + + resetDownloadVariables(): void { + this.downloadedBytes = 0; + this.totalBytes = 0; + this.startTime = 0; + this.downloadSpeed = 0; + } +} \ No newline at end of file