mirror of
https://github.com/modrinth/code.git
synced 2026-08-31 03:55:59 +00:00
fix: download multiple files immediately triggers blocking
This commit is contained in:
@@ -58,7 +58,11 @@
|
||||
<template v-if="showDependencyDownloadActions" #actions>
|
||||
<div class="flex flex-wrap justify-end gap-2">
|
||||
<ButtonStyled>
|
||||
<button :disabled="!!downloadingActionType" @click="downloadSelectedVersionZip">
|
||||
<button
|
||||
class="!shadow-none"
|
||||
:disabled="!!downloadingActionType"
|
||||
@click="downloadSelectedVersionZip"
|
||||
>
|
||||
<SpinnerIcon
|
||||
v-if="downloadingActionType === 'zip'"
|
||||
aria-hidden="true"
|
||||
@@ -70,6 +74,7 @@
|
||||
</ButtonStyled>
|
||||
<ButtonStyled color="brand">
|
||||
<button
|
||||
class="!shadow-none"
|
||||
:disabled="!!downloadingActionType || !dependencyDownloadFilesLoaded"
|
||||
@click="downloadSelectedVersionFilesWithDependencies"
|
||||
>
|
||||
@@ -199,6 +204,7 @@ const dependencyDownloadFilesLoaded = ref(false)
|
||||
const downloadingActionType = ref<DownloadActionType | null>(null)
|
||||
const MODAL_CLOSE_STATE_RESET_MS = 350
|
||||
const DOWNLOAD_URL_REVOKE_MS = 60000
|
||||
const DOWNLOAD_STAGGER_MS = 500
|
||||
let closeStateResetTimeout: ReturnType<typeof setTimeout> | null = null
|
||||
|
||||
const routeProjectId = computed(() => showProjectId.value ?? props.projectId ?? null)
|
||||
@@ -481,15 +487,10 @@ async function downloadSelectedVersionZip() {
|
||||
try {
|
||||
const zip = new JSZip()
|
||||
const usedFilenames = new Set<string>()
|
||||
const downloadedFiles = await downloadFileBlobs(files)
|
||||
|
||||
for (const file of files) {
|
||||
const response = await fetch(file.href)
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to download ${file.filename}`)
|
||||
}
|
||||
|
||||
zip.file(uniqueFilename(file.filename, usedFilenames), await response.blob())
|
||||
for (const file of downloadedFiles) {
|
||||
zip.file(uniqueFilename(file.filename, usedFilenames), file.blob)
|
||||
}
|
||||
|
||||
downloadBlob(
|
||||
@@ -523,11 +524,7 @@ async function downloadSelectedVersionFilesWithDependencies() {
|
||||
...dependencyDownloadFiles.value,
|
||||
])
|
||||
|
||||
const downloadedFiles = await Promise.all(files.map(downloadFileBlob))
|
||||
|
||||
for (const file of downloadedFiles) {
|
||||
downloadBlob(file.blob, file.filename)
|
||||
}
|
||||
await downloadFiles(files)
|
||||
|
||||
emit('download')
|
||||
} catch (error) {
|
||||
@@ -542,6 +539,10 @@ async function downloadSelectedVersionFilesWithDependencies() {
|
||||
}
|
||||
}
|
||||
|
||||
async function downloadFileBlobs(files: DownloadableFile[]): Promise<DownloadedFile[]> {
|
||||
return Promise.all(files.map((file) => downloadFileBlob(file)))
|
||||
}
|
||||
|
||||
async function downloadFileBlob(file: DownloadableFile): Promise<DownloadedFile> {
|
||||
const response = await fetch(file.href)
|
||||
|
||||
@@ -555,6 +556,15 @@ async function downloadFileBlob(file: DownloadableFile): Promise<DownloadedFile>
|
||||
}
|
||||
}
|
||||
|
||||
async function downloadFiles(files: DownloadableFile[]) {
|
||||
await Promise.all(
|
||||
files.map(async (file, index) => {
|
||||
await delay(DOWNLOAD_STAGGER_MS * index)
|
||||
downloadFileLink(file)
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
function dedupeDownloadFiles(files: DownloadableFile[]) {
|
||||
const result: DownloadableFile[] = []
|
||||
const hrefs = new Set<string>()
|
||||
@@ -580,6 +590,15 @@ function downloadBlob(blob: Blob, filename: string) {
|
||||
window.setTimeout(() => URL.revokeObjectURL(url), DOWNLOAD_URL_REVOKE_MS)
|
||||
}
|
||||
|
||||
function downloadFileLink(file: DownloadableFile) {
|
||||
const link = document.createElement('a')
|
||||
link.href = file.href
|
||||
link.download = file.filename
|
||||
document.body.appendChild(link)
|
||||
link.click()
|
||||
link.remove()
|
||||
}
|
||||
|
||||
function selectedVersionZipFilename() {
|
||||
if (!project.value || !selectedVersion.value) return 'download.zip'
|
||||
|
||||
@@ -650,7 +669,11 @@ function clearCloseStateResetTimeout() {
|
||||
|
||||
async function waitForCloseStateReset() {
|
||||
if (!closeStateResetTimeout) return
|
||||
await new Promise((resolve) => setTimeout(resolve, MODAL_CLOSE_STATE_RESET_MS))
|
||||
await delay(MODAL_CLOSE_STATE_RESET_MS)
|
||||
}
|
||||
|
||||
async function delay(ms: number) {
|
||||
await new Promise((resolve) => setTimeout(resolve, ms))
|
||||
}
|
||||
|
||||
async function loadProjectForModal(forceRefetch: boolean) {
|
||||
|
||||
Reference in New Issue
Block a user