Files
WarpBox/static/js/box.js
Daniel Legt 698166d23d feat(server): track upload status via manifest and /status API
- Persist per-box file metadata in a .warpbox.json manifest, including IDs and status fields (pending/uploading/complete/failed)
- Add GET /box/:id/status to return current file states for clients polling upload progress
- Update upload handling to mark failures and completion in the manifest and decorate responses
- Add CSS states for loading/failed files and disable interactions for unavailable itemsfeat(server): track upload status via manifest and /status API

- Persist per-box file metadata in a .warpbox.json manifest, including IDs and status fields (pending/uploading/complete/failed)
- Add GET /box/:id/status to return current file states for clients polling upload progress
- Update upload handling to mark failures and completion in the manifest and decorate responses
- Add CSS states for loading/failed files and disable interactions for unavailable items
2026-04-27 17:33:52 +03:00

73 lines
2.1 KiB
JavaScript

const boxPanel = document.querySelector(".box-panel[data-box-id]");
const boxStatus = document.querySelector(".box-statusbar span:first-child");
document.querySelectorAll('.box-file[aria-disabled="true"]').forEach((item) => {
item.addEventListener("click", (event) => {
if (item.getAttribute("aria-disabled") === "true") {
event.preventDefault();
}
});
});
function updateBoxFile(file) {
const item = document.querySelector(`.box-file[data-file-id="${file.id}"]`);
if (!item) {
return;
}
const meta = item.querySelector(".box-file-meta");
const isComplete = file.status === "complete";
const isFailed = file.status === "failed";
item.classList.toggle("is-complete", isComplete);
item.classList.toggle("is-failed", isFailed);
item.classList.toggle("is-loading", !isComplete && !isFailed);
item.dataset.status = file.status;
item.title = file.title;
if (isComplete) {
item.href = file.download_path;
item.setAttribute("download", "");
item.removeAttribute("aria-disabled");
} else {
item.href = "#";
item.removeAttribute("download");
item.setAttribute("aria-disabled", "true");
}
if (meta) {
meta.textContent = `${file.status_label} · ${file.size_label}`;
}
}
async function refreshBoxStatus() {
if (!boxPanel) {
return false;
}
const boxID = boxPanel.dataset.boxId;
const response = await fetch(`/box/${boxID}/status`);
if (!response.ok) {
return false;
}
const result = await response.json();
result.files.forEach(updateBoxFile);
if (boxStatus) {
const completeCount = result.files.filter((file) => file.status === "complete").length;
boxStatus.textContent = `${completeCount}/${result.files.length} ready`;
}
return result.files.some((file) => file.status === "pending" || file.status === "uploading");
}
if (boxPanel) {
const timer = setInterval(async () => {
const hasLoadingFiles = await refreshBoxStatus();
if (!hasLoadingFiles) {
clearInterval(timer);
}
}, 1500);
}