diff --git a/frontend/src/components/prompts/Upload.vue b/frontend/src/components/prompts/Upload.vue index bb8ec40e..bb4e69cc 100644 --- a/frontend/src/components/prompts/Upload.vue +++ b/frontend/src/components/prompts/Upload.vue @@ -37,11 +37,13 @@ import { useI18n } from "vue-i18n"; import { useRoute } from "vue-router"; import { useFileStore } from "@/stores/file"; import { useLayoutStore } from "@/stores/layout"; +import { useAuthStore } from "@/stores/auth"; import * as upload from "@/utils/upload"; const { t } = useI18n(); const route = useRoute(); +const authStore = useAuthStore(); const fileStore = useFileStore(); const layoutStore = useLayoutStore(); @@ -54,6 +56,11 @@ const uploadInput = (event: Event) => { if (files === null) return; let folder_upload = !!files[0].webkitRelativePath; + let uploadsLimit = 1 + if (authStore.user!=null){ + uploadsLimit = authStore.user.uploadsLimit + } + const uploadFiles: UploadList = []; for (let i = 0; i < files.length; i++) { @@ -77,19 +84,19 @@ const uploadInput = (event: Event) => { action: (event: Event) => { event.preventDefault(); layoutStore.closeHovers(); - upload.handleFiles(uploadFiles, path, false); + upload.handleFiles(uploadFiles, path, uploadsLimit); }, confirm: (event: Event) => { event.preventDefault(); layoutStore.closeHovers(); - upload.handleFiles(uploadFiles, path, true); + upload.handleFiles(uploadFiles, path, uploadsLimit, true); }, }); return; } - upload.handleFiles(uploadFiles, path); + upload.handleFiles(uploadFiles, path, uploadsLimit); }; const openUpload = (isFolder: boolean) => { diff --git a/frontend/src/i18n/en.json b/frontend/src/i18n/en.json index 00d43b9d..b148367a 100644 --- a/frontend/src/i18n/en.json +++ b/frontend/src/i18n/en.json @@ -236,7 +236,8 @@ "userManagement": "User Management", "userUpdated": "User updated!", "username": "Username", - "users": "Users" + "users": "Users", + "uploadsLimit":"Limit of concurrent uploads" }, "sidebar": { "help": "Help", diff --git a/frontend/src/i18n/zh-cn.json b/frontend/src/i18n/zh-cn.json index 1aea4134..06f97ef0 100644 --- a/frontend/src/i18n/zh-cn.json +++ b/frontend/src/i18n/zh-cn.json @@ -236,7 +236,8 @@ "userManagement": "用户管理", "userUpdated": "用户已更新!", "username": "用户名", - "users": "用户" + "users": "用户", + "uploadsLimit":"上传并行任务数限制" }, "sidebar": { "help": "帮助", diff --git a/frontend/src/i18n/zh-tw.json b/frontend/src/i18n/zh-tw.json index fdb2447c..f9f4c840 100644 --- a/frontend/src/i18n/zh-tw.json +++ b/frontend/src/i18n/zh-tw.json @@ -236,7 +236,8 @@ "userManagement": "使用者管理", "userUpdated": "使用者已更新!", "username": "使用者名稱", - "users": "使用者" + "users": "使用者", + "uploadsLimit":"上傳並行任務數限制" }, "sidebar": { "help": "幫助", diff --git a/frontend/src/stores/upload.ts b/frontend/src/stores/upload.ts index 4e814454..88a00520 100644 --- a/frontend/src/stores/upload.ts +++ b/frontend/src/stores/upload.ts @@ -4,8 +4,6 @@ import { files as api } from "@/api"; import throttle from "lodash/throttle"; import buttons from "@/utils/buttons"; -// TODO: make this into a user setting -const UPLOADS_LIMIT = 5; const beforeUnload = (event: Event) => { event.preventDefault(); @@ -145,7 +143,7 @@ export const useUploadStore = defineStore("upload", { removeJob(id: number) { delete this.uploads[id]; }, - upload(item: UploadItem) { + upload(item: UploadItem,uploadsLimit:number) { const uploadsCount = Object.keys(this.uploads).length; const isQueueEmpty = this.queue.length == 0; @@ -157,17 +155,17 @@ export const useUploadStore = defineStore("upload", { } this.addJob(item); - this.processUploads(); + this.processUploads(uploadsLimit); }, - finishUpload(item: UploadItem) { + finishUpload(item: UploadItem,uploadsLimit:number) { this.setProgress({ id: item.id, loaded: item.file.size > 0 }); this.removeJob(item.id); - this.processUploads(); + this.processUploads(uploadsLimit); }, - async processUploads() { + async processUploads(uploadsLimit:number) { const uploadsCount = Object.keys(this.uploads).length; - const isBellowLimit = uploadsCount < UPLOADS_LIMIT; + const isBellowLimit = uploadsCount < uploadsLimit; const isQueueEmpty = this.queue.length == 0; const isUploadsEmpty = uploadsCount == 0; @@ -204,7 +202,7 @@ export const useUploadStore = defineStore("upload", { .catch(this.setError); } - this.finishUpload(item); + this.finishUpload(item,uploadsLimit); } }, setUploadSpeed(value: number) { diff --git a/frontend/src/types/settings.d.ts b/frontend/src/types/settings.d.ts index a2c19f76..f7d2c208 100644 --- a/frontend/src/types/settings.d.ts +++ b/frontend/src/types/settings.d.ts @@ -20,6 +20,7 @@ interface SettingsDefaults { commands: any[]; hideDotfiles: boolean; dateFormat: boolean; + uploadsLimit:number; } interface SettingsBranding { diff --git a/frontend/src/types/user.d.ts b/frontend/src/types/user.d.ts index b81806fc..a44aaf84 100644 --- a/frontend/src/types/user.d.ts +++ b/frontend/src/types/user.d.ts @@ -13,6 +13,7 @@ interface IUser { dateFormat: boolean; viewMode: ViewModeType; sorting?: Sorting; + uploadsLimit:number; } type ViewModeType = "list" | "mosaic" | "mosaic gallery"; @@ -30,6 +31,7 @@ interface IUserForm { hideDotfiles?: boolean; singleClick?: boolean; dateFormat?: boolean; + uploadsLimit:number; } interface Permissions { diff --git a/frontend/src/utils/upload.ts b/frontend/src/utils/upload.ts index e7ce8bec..0358cf34 100644 --- a/frontend/src/utils/upload.ts +++ b/frontend/src/utils/upload.ts @@ -123,7 +123,8 @@ function detectType(mimetype: string): ResourceType { export function handleFiles( files: UploadList, base: string, - overwrite = false + uploadsLimit:number, + overwrite = false, ) { const uploadStore = useUploadStore(); @@ -149,6 +150,6 @@ export function handleFiles( ...(!file.isDir && { type: detectType((file.file as File).type) }), }; - uploadStore.upload(item); + uploadStore.upload(item,uploadsLimit); } } diff --git a/frontend/src/views/files/FileListing.vue b/frontend/src/views/files/FileListing.vue index a26ac67e..9ad61294 100644 --- a/frontend/src/views/files/FileListing.vue +++ b/frontend/src/views/files/FileListing.vue @@ -731,25 +731,30 @@ const drop = async (event: DragEvent) => { let conflict = upload.checkConflict(files, items); + let uploadsLimit = 1 + if (authStore.user!=null){ + uploadsLimit = authStore.user.uploadsLimit + } + if (conflict) { layoutStore.showHover({ prompt: "replace", action: (event: Event) => { event.preventDefault(); layoutStore.closeHovers(); - upload.handleFiles(files, path, false); + upload.handleFiles(files, path,uploadsLimit); }, confirm: (event: Event) => { event.preventDefault(); layoutStore.closeHovers(); - upload.handleFiles(files, path, true); + upload.handleFiles(files, path,uploadsLimit, true,); }, }); return; } - upload.handleFiles(files, path); + upload.handleFiles(files, path,uploadsLimit); }; const uploadInput = (event: Event) => { @@ -776,25 +781,30 @@ const uploadInput = (event: Event) => { let path = route.path.endsWith("/") ? route.path : route.path + "/"; let conflict = upload.checkConflict(uploadFiles, fileStore.req!.items); + let uploadsLimit = 1 + if (authStore.user!=null){ + uploadsLimit = authStore.user.uploadsLimit + } + if (conflict) { layoutStore.showHover({ prompt: "replace", action: (event: Event) => { event.preventDefault(); layoutStore.closeHovers(); - upload.handleFiles(uploadFiles, path, false); + upload.handleFiles(uploadFiles, path, uploadsLimit); }, confirm: (event: Event) => { event.preventDefault(); layoutStore.closeHovers(); - upload.handleFiles(uploadFiles, path, true); + upload.handleFiles(uploadFiles, path, uploadsLimit,true); }, }); return; } - upload.handleFiles(uploadFiles, path); + upload.handleFiles(uploadFiles, path,uploadsLimit); }; const resetOpacity = () => { diff --git a/frontend/src/views/settings/Profile.vue b/frontend/src/views/settings/Profile.vue index c677092f..6f1cac72 100644 --- a/frontend/src/views/settings/Profile.vue +++ b/frontend/src/views/settings/Profile.vue @@ -19,11 +19,18 @@ {{ t("settings.setDateFormat") }}
+