0.10.2 Download Files

This commit is contained in:
2026-03-15 12:15:46 +00:00
parent 52ef155c7c
commit 7d6c154909
12 changed files with 1313 additions and 28 deletions

View File

@@ -111,6 +111,69 @@ async function request(path, options = {}) {
return response.text();
}
function resolveFilenameFromDisposition(contentDisposition, fallback = 'download.zip') {
const raw = String(contentDisposition || '').trim();
if (!raw) {
return fallback;
}
const encodedMatch = raw.match(/filename\*\s*=\s*UTF-8''([^;]+)/i);
if (encodedMatch?.[1]) {
try {
return decodeURIComponent(encodedMatch[1]);
} catch (_error) {
// ignore malformed content-disposition values
}
}
const plainMatch = raw.match(/filename\s*=\s*"([^"]+)"/i) || raw.match(/filename\s*=\s*([^;]+)/i);
if (plainMatch?.[1]) {
return String(plainMatch[1]).trim();
}
return fallback;
}
async function download(path, options = {}) {
const response = await fetch(`${API_BASE}${path}`, {
headers: options?.headers || {},
method: options?.method || 'GET'
});
if (!response.ok) {
let errorPayload = null;
let message = `HTTP ${response.status}`;
try {
errorPayload = await response.json();
message = errorPayload?.error?.message || message;
} catch (_error) {
// ignore parse errors
}
const error = new Error(message);
error.status = response.status;
error.details = errorPayload?.error?.details || null;
throw error;
}
const blob = await response.blob();
const objectUrl = URL.createObjectURL(blob);
const link = document.createElement('a');
const fallbackFilename = String(options?.filename || 'download.zip').trim() || 'download.zip';
const filename = resolveFilenameFromDisposition(response.headers.get('content-disposition'), fallbackFilename);
link.href = objectUrl;
link.download = filename;
document.body.appendChild(link);
link.click();
link.remove();
window.setTimeout(() => URL.revokeObjectURL(objectUrl), 1000);
return {
filename,
sizeBytes: blob.size
};
}
async function requestWithXhr(path, options = {}) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
@@ -630,6 +693,11 @@ export const api = {
afterMutationInvalidate(['/history', '/pipeline/queue']);
return result;
},
downloadJobArchive(jobId, target = 'raw') {
const query = new URLSearchParams();
query.set('target', String(target || 'raw').trim());
return download(`/history/${jobId}/download?${query.toString()}`);
},
getJob(jobId, options = {}) {
const query = new URLSearchParams();
const includeLiveLog = Boolean(options.includeLiveLog);