feat: add thumbnail metadata and download endpoint

- Extend `BoxFile` with thumbnail path/status fields and internal URL
- Populate `ThumbnailURL` when a thumbnail path is present during decoration
- Add `/box/:id/thumbnails/:file_id` route and handler to serve JPEG thumbnails
- Introduce thumbnail status constants to standardize processing state reportingfeat: add thumbnail metadata and download endpoint

- Extend `BoxFile` with thumbnail path/status fields and internal URL
- Populate `ThumbnailURL` when a thumbnail path is present during decoration
- Add `/box/:id/thumbnails/:file_id` route and handler to serve JPEG thumbnails
- Introduce thumbnail status constants to standardize processing state reporting
This commit is contained in:
2026-04-28 18:44:16 +03:00
parent c1489d1fbb
commit f1600faa8d
12 changed files with 400 additions and 17 deletions

View File

@@ -16,12 +16,14 @@ function updateBoxFile(file) {
}
const meta = item.querySelector(".box-file-meta");
const icon = item.querySelector(".box-file-icon");
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.classList.toggle("has-thumbnail", Boolean(file.thumbnail_path));
item.dataset.status = file.status;
item.title = file.title;
@@ -38,6 +40,10 @@ function updateBoxFile(file) {
if (meta) {
meta.textContent = `${file.status_label} · ${file.size_label}`;
}
if (icon) {
icon.src = file.thumbnail_path || file.icon_path;
}
}
async function refreshBoxStatus() {
@@ -59,7 +65,11 @@ async function refreshBoxStatus() {
boxStatus.textContent = `${completeCount}/${result.files.length} ready`;
}
return result.files.some((file) => file.status === "pending" || file.status === "uploading");
return result.files.some((file) => {
const isUploading = file.status === "pending" || file.status === "uploading";
const isWaitingForThumbnail = file.status === "complete" && !file.thumbnail_status && !file.thumbnail_path;
return isUploading || isWaitingForThumbnail || file.thumbnail_status === "processing";
});
}
if (boxPanel) {