fix: file uploading state admonition

This commit is contained in:
Calum H. (IMB11)
2026-05-16 17:03:56 +01:00
parent 02a7774722
commit 680301ed9d
9 changed files with 78 additions and 38 deletions
@@ -1,18 +1,14 @@
<template>
<Admonition type="info" :progress="overallProgress" progress-color="blue">
<Admonition type="info" :progress="displayProgress" progress-color="blue">
<template #icon>
<UploadIcon class="h-6 w-6 flex-none text-brand-blue" />
</template>
<template #header>
{{
state.currentFileName
? `Uploading ${state.currentFileName} (${state.completedFiles}/${state.totalFiles})`
: `Uploading files (${state.completedFiles}/${state.totalFiles})`
}}
{{ headerText }}
</template>
<span class="text-secondary">
{{ formatBytes(state.uploadedBytes) }} / {{ formatBytes(state.totalBytes) }} ({{
Math.round(overallProgress * 100)
{{ formatBytes(displayUploadedBytes) }} / {{ formatBytes(state.totalBytes) }} ({{
Math.round(displayProgress * 100)
}}%)
</span>
<template v-if="cancelUpload" #top-right-actions>
@@ -39,9 +35,32 @@ const ctx = injectModrinthServerContext()
const state = computed(() => ctx.uploadState.value)
const cancelUpload = computed(() => ctx.cancelUpload.value)
const overallProgress = computed(() => {
const headerText = computed(() => {
const s = state.value
if (!s.isUploading || s.totalFiles === 0) return 0
return Math.min((s.completedFiles + s.currentFileProgress) / s.totalFiles, 1)
if (s.currentFileName) {
return `Uploading ${s.currentFileName} (${currentFileNumber.value}/${s.totalFiles})`
}
return `Uploading files (${s.completedFiles}/${s.totalFiles})`
})
const currentFileNumber = computed(() => {
const s = state.value
if (s.totalFiles === 0) return 0
return Math.min(s.completedFiles + 1, s.totalFiles)
})
const displayUploadedBytes = computed(() => {
const s = state.value
if (s.totalBytes <= 0) return s.uploadedBytes
return Math.min(s.uploadedBytes, s.totalBytes)
})
const displayProgress = computed(() => {
const s = state.value
if (!s.isUploading) return 0
if (s.totalBytes > 0) {
return displayUploadedBytes.value / s.totalBytes
}
return 0
})
</script>
@@ -349,7 +349,6 @@ export function useServerManageCoreRuntime(options: UseServerManageCoreRuntimeOp
const uploadState = ref<UploadState>({
isUploading: false,
currentFileName: null,
currentFileProgress: 0,
uploadedBytes: 0,
totalBytes: 0,
completedFiles: 0,
@@ -702,31 +702,49 @@ function handleUploadFiles() {
input.onchange = async () => {
if (!input.files) return
const files = Array.from(input.files)
if (files.length === 0) return
const wid = worldId.value
if (!wid) return
const totalBytes = files.reduce((sum, f) => sum + f.size, 0)
uploadState.value = {
isUploading: true,
currentFileName: null,
currentFileProgress: 0,
currentFileName: files[0]?.name ?? null,
uploadedBytes: 0,
totalBytes: files.reduce((sum, f) => sum + f.size, 0),
totalBytes,
completedFiles: 0,
totalFiles: files.length,
}
const cumulativeFileBytes = files.reduce<number[]>((out, file) => {
out.push((out[out.length - 1] ?? 0) + file.size)
return out
}, [])
function updateUploadProgress(loaded: number, total: number) {
const uploadedBytes =
total > 0 ? Math.round((Math.min(loaded, total) / total) * totalBytes) : loaded
const clampedUploadedBytes = Math.min(uploadedBytes, totalBytes)
const completedFiles = cumulativeFileBytes.filter(
(bytes) => bytes <= clampedUploadedBytes,
).length
const currentFileIndex = Math.min(completedFiles, files.length - 1)
uploadState.value.uploadedBytes = clampedUploadedBytes
uploadState.value.completedFiles = completedFiles
uploadState.value.currentFileName = files[currentFileIndex]?.name ?? null
}
const handle = client.kyros.content_v1.uploadAddonFile(wid, files, {
onProgress: (p) => {
uploadState.value.currentFileProgress = p.progress
uploadState.value.uploadedBytes = p.loaded
uploadState.value.totalBytes = p.total
},
onProgress: ({ loaded, total }) => updateUploadProgress(loaded, total),
})
cancelUpload.value = () => handle.cancel()
try {
await handle.promise
uploadState.value.uploadedBytes = totalBytes
uploadState.value.completedFiles = files.length
uploadState.value.currentFileName = files[files.length - 1]?.name ?? null
await contentQuery.refetch()
} catch (err) {
if (err instanceof Error && err.message === 'Upload cancelled') return
@@ -740,7 +758,6 @@ function handleUploadFiles() {
uploadState.value = {
isUploading: false,
currentFileName: null,
currentFileProgress: 0,
uploadedBytes: 0,
totalBytes: 0,
completedFiles: 0,
@@ -374,7 +374,6 @@ async function uploadFiles(files: File[]) {
uploadState.value = {
isUploading: true,
currentFileName: files[0].name,
currentFileProgress: 0,
uploadedBytes: 0,
totalBytes,
completedFiles: 0,
@@ -389,13 +388,11 @@ async function uploadFiles(files: File[]) {
const filePath = `${currentPath.value}/${file.name}`.replace('//', '/')
uploadState.value.currentFileName = file.name
uploadState.value.currentFileProgress = 0
try {
const uploader = client.kyros.files_v0.uploadFile(filePath, file, {
onProgress: ({ progress }) => {
uploadState.value.currentFileProgress = progress
uploadState.value.uploadedBytes = completedBytes + Math.round(file.size * progress)
onProgress: ({ loaded }) => {
uploadState.value.uploadedBytes = completedBytes + Math.min(loaded, file.size)
},
})
activeUploadCancel = () => uploader.cancel()
@@ -420,7 +417,6 @@ async function uploadFiles(files: File[]) {
uploadState.value = {
isUploading: false,
currentFileName: null,
currentFileProgress: 0,
uploadedBytes: 0,
totalBytes: 0,
completedFiles: 0,
@@ -46,7 +46,6 @@ const meta = {
const uploadState = ref<UploadState>({
isUploading: false,
currentFileName: null,
currentFileProgress: 0,
uploadedBytes: 0,
totalBytes: 0,
completedFiles: 0,
@@ -52,7 +52,6 @@ const meta = {
const uploadState = ref<UploadState>({
isUploading: true,
currentFileName: 'resourcepack.zip',
currentFileProgress: 0.2,
uploadedBytes: 20_000,
totalBytes: 100_000,
completedFiles: 1,