Skip to content
Open
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/lang/en/home.json
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,8 @@
"success": "Success",
"error": "Error",
"back": "Back to Upload",
"clear_done": "Clear Done"
"clear_done": "Clear Done",
"retry": "Retry"
},
"local_settings": {
"aria2_rpc_url": "Aria2 RPC URL",
Expand Down
3 changes: 3 additions & 0 deletions src/lang/en/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@
"max_index_depth-tips": "max depth of index",
"max_server_download_speed": "Max server download speed",
"max_server_upload_speed": "Max server upload speed",
"multipart_chunk_size": "Multipart upload chunk size (MB)",
"multipart_chunk_size-tips": "chunk size of multipart upload in MB (positive integer), keep it under your CDN's request body limit; each active session buffers up to 8 chunks on the server's disk",
"multipart_enabled": "Enable multipart upload",
"non_efs_zip_encoding": "Alternative encoding for ZIP Files",
"ocr_api": "Ocr api",
"offline_download_task_threads_num": "Offline download task threads num",
Expand Down
42 changes: 37 additions & 5 deletions src/pages/home/uploads/Upload.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import { File2Upload, traverseFileTree } from "./util"
import { SelectWrapper } from "~/components"
import { getUploads } from "./uploads"

const UploadFile = (props: UploadFileProps) => {
const UploadFile = (props: UploadFileProps & { onRetry?: () => void }) => {
const t = useT()
return (
<VStack
Expand Down Expand Up @@ -56,7 +56,19 @@ const UploadFile = (props: UploadFileProps) => {
</Badge>
<Text>{getFileSize(props.speed)}/s</Text>
</HStack>
<Text color="$neutral11">{getFileSize(props.size)}</Text>
<HStack spacing="$2">
<Show when={props.status === "error" && props.onRetry}>
<Button
compact
size="xs"
colorScheme="accent"
onClick={() => props.onRetry?.()}
>
{t("home.upload.retry")}
</Button>
</Show>
<Text color="$neutral11">{getFileSize(props.size)}</Text>
</HStack>
</HStack>
<Progress
w="$full"
Expand Down Expand Up @@ -91,11 +103,14 @@ const Upload = () => {
}
let fileInput!: HTMLInputElement
let folderInput!: HTMLInputElement
// keep the File handles around so a failed row can be retried in place
const fileMap = new Map<string, File>()
const handleAddFiles = async (files: File[]) => {
if (files.length === 0) return
setUploading(true)
for (const file of files) {
const upload = File2Upload(file)
fileMap.set(upload.path, file)
setUploadFiles("uploads", (uploads) => [...uploads, upload])
}
for await (const ms of asyncPool(3, files, handleFile)) {
Expand All @@ -112,6 +127,17 @@ const Upload = () => {
// All upload methods are available by default
const uploaders = getUploads()
const [curUploader, setCurUploader] = createSignal(uploaders[0])
// multipart sessions are synchronous pipelines with their own progress and
// retry semantics; "add as task" does not apply to them
const asTaskUnsupported = () => curUploader()?.name === "Multipart"
const retryFile = (path: string) => {
const file = fileMap.get(path)
if (!file) return
setUpload(path, "msg", "")
setUpload(path, "progress", 0)
setUpload(path, "speed", 0)
handleFile(file)
}
const handleFile = async (file: File) => {
const path = file.webkitRelativePath ? file.webkitRelativePath : file.name
setUpload(path, "status", "uploading")
Expand All @@ -124,7 +150,7 @@ const Upload = () => {
(key, value) => {
setUpload(path, key, value)
},
uploadConfig.asTask,
asTaskUnsupported() ? false : uploadConfig.asTask,
uploadConfig.overwrite,
uploadConfig.rapid,
)
Expand Down Expand Up @@ -173,7 +199,12 @@ const Upload = () => {
</Show>
</HStack>
<For each={uploadFiles.uploads}>
{(upload) => <UploadFile {...upload} />}
{(upload) => (
<UploadFile
{...upload}
onRetry={() => retryFile(upload.path)}
/>
)}
</For>
</>
}
Expand Down Expand Up @@ -303,7 +334,8 @@ const Upload = () => {
direction={{ "@initial": "column", "@md": "row" }}
>
<Checkbox
checked={uploadConfig.asTask}
checked={!asTaskUnsupported() && uploadConfig.asTask}
disabled={asTaskUnsupported()}
onChange={() => {
setUploadConfig({ asTask: !uploadConfig.asTask })
}}
Expand Down
Loading