feat: B3 uit voor veilige archive-downloads - cancel knop toegevoegd
This commit is contained in:
+91
-3
@@ -86,6 +86,8 @@ let downloadProgressState = {
|
||||
archiveLabel: "",
|
||||
totalItems: 0,
|
||||
requestKey: null,
|
||||
taskId: null,
|
||||
cancelRequested: false,
|
||||
};
|
||||
let folderUploadPlanState = {
|
||||
targetPane: "left",
|
||||
@@ -336,6 +338,7 @@ function downloadModalElements() {
|
||||
count: document.getElementById("download-modal-count"),
|
||||
progressBar: document.getElementById("download-modal-progress-bar"),
|
||||
status: document.getElementById("download-modal-status"),
|
||||
cancelButton: document.getElementById("download-modal-cancel-btn"),
|
||||
closeButton: document.getElementById("download-modal-close-btn"),
|
||||
};
|
||||
}
|
||||
@@ -400,6 +403,8 @@ function updateDownloadModalDisplay(info) {
|
||||
elements.count.textContent = info.countText || "";
|
||||
elements.status.textContent = info.statusText || "";
|
||||
elements.progressBar.style.width = `${Math.max(0, Math.min(100, info.percent || 0))}%`;
|
||||
elements.cancelButton.disabled = !!info.cancelDisabled;
|
||||
elements.cancelButton.classList.toggle("hidden", !info.cancelVisible);
|
||||
elements.closeButton.disabled = !!info.active;
|
||||
elements.closeButton.classList.toggle("hidden", !!info.active);
|
||||
}
|
||||
@@ -410,6 +415,8 @@ function openZipDownloadModal(selectedItems) {
|
||||
downloadProgressState.archiveLabel = "ZIP archive";
|
||||
downloadProgressState.totalItems = selectedItems.length;
|
||||
downloadProgressState.requestKey = zipDownloadRequestKey(requestPaths);
|
||||
downloadProgressState.taskId = null;
|
||||
downloadProgressState.cancelRequested = false;
|
||||
setDownloadModalVisible(true);
|
||||
updateDownloadModalDisplay({
|
||||
active: true,
|
||||
@@ -418,6 +425,8 @@ function openZipDownloadModal(selectedItems) {
|
||||
countText: "Preparing zip download",
|
||||
statusText: "Preparing download...",
|
||||
percent: 20,
|
||||
cancelVisible: true,
|
||||
cancelDisabled: true,
|
||||
});
|
||||
requestAnimationFrame(() => {
|
||||
if (!downloadProgressState.active) {
|
||||
@@ -430,12 +439,15 @@ function openZipDownloadModal(selectedItems) {
|
||||
countText: "Zip preflight and packaging",
|
||||
statusText: "Preparing download...",
|
||||
percent: 55,
|
||||
cancelVisible: true,
|
||||
cancelDisabled: !downloadProgressState.taskId || downloadProgressState.cancelRequested,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function markZipDownloadReady(fileName) {
|
||||
downloadProgressState.active = false;
|
||||
downloadProgressState.cancelRequested = false;
|
||||
downloadProgressState.archiveLabel = fileName || "ZIP archive";
|
||||
updateDownloadModalDisplay({
|
||||
active: false,
|
||||
@@ -444,12 +456,14 @@ function markZipDownloadReady(fileName) {
|
||||
countText: "Browser download started",
|
||||
statusText: "Download started",
|
||||
percent: 100,
|
||||
cancelVisible: false,
|
||||
});
|
||||
window.setTimeout(closeDownloadModal, 480);
|
||||
}
|
||||
|
||||
function markZipDownloadFailed(err) {
|
||||
downloadProgressState.active = false;
|
||||
downloadProgressState.cancelRequested = false;
|
||||
updateDownloadModalDisplay({
|
||||
active: false,
|
||||
targetText: "Preparing download...",
|
||||
@@ -457,6 +471,21 @@ function markZipDownloadFailed(err) {
|
||||
countText: "Zip download failed",
|
||||
statusText: err.message || "Download failed",
|
||||
percent: 0,
|
||||
cancelVisible: false,
|
||||
});
|
||||
}
|
||||
|
||||
function markZipDownloadCancelled() {
|
||||
downloadProgressState.active = false;
|
||||
downloadProgressState.cancelRequested = false;
|
||||
updateDownloadModalDisplay({
|
||||
active: false,
|
||||
targetText: "Download cancelled",
|
||||
currentFileText: `Selection: ${selectedItemCountLabel(downloadProgressState.totalItems)}`,
|
||||
countText: "Zip download cancelled",
|
||||
statusText: "Download cancelled",
|
||||
percent: 0,
|
||||
cancelVisible: false,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -469,8 +498,10 @@ function updateZipDownloadTaskProgress(task) {
|
||||
targetText: "Preparing download...",
|
||||
currentFileText: task.current_item ? `Current: ${task.current_item}` : `Selection: ${selectedItemCountLabel(downloadProgressState.totalItems)}`,
|
||||
countText: task.total_items ? `${task.done_items || 0}/${task.total_items} top-level items` : "Preparing zip download",
|
||||
statusText: task.status === "ready" ? "Download started" : "Preparing download...",
|
||||
statusText: downloadProgressState.cancelRequested ? "Cancelling download..." : task.status === "ready" ? "Download started" : "Preparing download...",
|
||||
percent: task.status === "ready" ? 100 : 55,
|
||||
cancelVisible: true,
|
||||
cancelDisabled: !downloadProgressState.taskId || downloadProgressState.cancelRequested,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -484,6 +515,11 @@ async function waitForArchiveDownloadReady(taskId) {
|
||||
if (task.status === "ready") {
|
||||
return task;
|
||||
}
|
||||
if (task.status === "cancelled") {
|
||||
const err = new Error("Archive download was cancelled");
|
||||
err.code = "download_cancelled";
|
||||
throw err;
|
||||
}
|
||||
if (task.status === "failed") {
|
||||
const err = new Error(task.error_message || "Archive download failed");
|
||||
err.code = task.error_code || null;
|
||||
@@ -501,6 +537,8 @@ function closeDownloadModal() {
|
||||
downloadProgressState.archiveLabel = "";
|
||||
downloadProgressState.totalItems = 0;
|
||||
downloadProgressState.requestKey = null;
|
||||
downloadProgressState.taskId = null;
|
||||
downloadProgressState.cancelRequested = false;
|
||||
updateDownloadModalDisplay({
|
||||
active: false,
|
||||
targetText: "",
|
||||
@@ -508,6 +546,7 @@ function closeDownloadModal() {
|
||||
countText: "",
|
||||
statusText: "",
|
||||
percent: 0,
|
||||
cancelVisible: false,
|
||||
});
|
||||
setDownloadModalVisible(false);
|
||||
}
|
||||
@@ -679,6 +718,13 @@ async function startDownloadSelected() {
|
||||
const selected = selectedItems[0];
|
||||
if (zipDownload) {
|
||||
const created = await createArchiveDownloadTask(selectedPaths);
|
||||
downloadProgressState.taskId = created.task_id;
|
||||
updateZipDownloadTaskProgress({
|
||||
status: "preparing",
|
||||
current_item: null,
|
||||
done_items: 0,
|
||||
total_items: selectedItems.length,
|
||||
});
|
||||
const task = await waitForArchiveDownloadReady(created.task_id);
|
||||
startArchiveDownload(task.id, task.destination);
|
||||
markZipDownloadReady(task.destination);
|
||||
@@ -697,8 +743,13 @@ async function startDownloadSelected() {
|
||||
setStatus(`Download started: ${anchor.download}`);
|
||||
} catch (err) {
|
||||
if (zipDownload) {
|
||||
markZipDownloadFailed(err);
|
||||
setStatus("Download failed");
|
||||
if (err.code === "download_cancelled") {
|
||||
markZipDownloadCancelled();
|
||||
setStatus("Download cancelled");
|
||||
} else {
|
||||
markZipDownloadFailed(err);
|
||||
setStatus("Download failed");
|
||||
}
|
||||
} else {
|
||||
setActionError("Download", err);
|
||||
}
|
||||
@@ -1004,6 +1055,10 @@ async function getTaskRequest(taskId) {
|
||||
return apiRequest("GET", `/api/tasks/${encodeURIComponent(taskId)}`);
|
||||
}
|
||||
|
||||
async function cancelArchiveDownloadTask(taskId) {
|
||||
return apiRequest("POST", `/api/files/download/archive/${encodeURIComponent(taskId)}/cancel`);
|
||||
}
|
||||
|
||||
function startArchiveDownload(taskId, fileName) {
|
||||
const anchor = document.createElement("a");
|
||||
anchor.href = `/api/files/download/archive/${encodeURIComponent(taskId)}`;
|
||||
@@ -1013,6 +1068,31 @@ function startArchiveDownload(taskId, fileName) {
|
||||
anchor.remove();
|
||||
}
|
||||
|
||||
async function requestArchiveDownloadCancel() {
|
||||
if (!downloadProgressState.active || !downloadProgressState.taskId || downloadProgressState.cancelRequested) {
|
||||
return;
|
||||
}
|
||||
downloadProgressState.cancelRequested = true;
|
||||
updateDownloadModalDisplay({
|
||||
active: true,
|
||||
targetText: "Preparing download...",
|
||||
currentFileText: `Selection: ${selectedItemCountLabel(downloadProgressState.totalItems)}`,
|
||||
countText: "Zip download cancellation requested",
|
||||
statusText: "Cancelling download...",
|
||||
percent: 55,
|
||||
cancelVisible: true,
|
||||
cancelDisabled: true,
|
||||
});
|
||||
try {
|
||||
await cancelArchiveDownloadTask(downloadProgressState.taskId);
|
||||
} catch (err) {
|
||||
if (err.code !== "download_not_cancellable") {
|
||||
downloadProgressState.cancelRequested = false;
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function uploadFileRequest(targetPath, file, overwrite = false) {
|
||||
const formData = new FormData();
|
||||
formData.append("target_path", targetPath);
|
||||
@@ -4164,6 +4244,14 @@ function setupEvents() {
|
||||
};
|
||||
}
|
||||
const downloadModal = downloadModalElements();
|
||||
if (downloadModal.cancelButton) {
|
||||
downloadModal.cancelButton.onclick = () => {
|
||||
requestArchiveDownloadCancel().catch((err) => {
|
||||
markZipDownloadFailed(err);
|
||||
setStatus("Download failed");
|
||||
});
|
||||
};
|
||||
}
|
||||
if (downloadModal.closeButton) {
|
||||
downloadModal.closeButton.onclick = closeDownloadModal;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user