feat(upload): warn on large uploads over slow/metered connections
All checks were successful
Build and Publish Docker Image / deploy (push) Successful in 1m54s

Detects if the user is on a slow (2G/3G) or metered (saveData) connection
and prompts them with a confirmation dialog if they attempt to upload
files totaling 200MB or more.

This prevents accidental high data usage and warns users about potential
long upload times. Also includes the dialogs JS and CSS in the base
layout to support the confirmation modal.
This commit is contained in:
2026-06-08 13:34:05 +03:00
parent ead4cd7492
commit 0b4487ac2e
4 changed files with 621 additions and 0 deletions

View File

@@ -17,6 +17,7 @@
const RESUMABLE_SESSIONS_KEY = "warpbox-resumable-sessions";
const SHARE_CACHE = "warpbox-share-target-v1";
const SHARE_LATEST_KEY = "/__warpbox_share_target__/latest";
const CELLULAR_WARNING_THRESHOLD_BYTES = 200 * 1024 * 1024;
if (!form || !dropZone || !fileInput) {
return;
@@ -106,6 +107,12 @@
if (!validateSelectedFilesWithinLimit(selectedFiles)) {
return;
}
if (isSlowOrMeteredConnection() && totalSelectedBytes(selectedFiles) >= CELLULAR_WARNING_THRESHOLD_BYTES) {
const proceed = await confirmCellularUpload(selectedFiles);
if (!proceed) {
return;
}
}
const submit = form.querySelector("button[type='submit']");
const formData = uploadFormData();
@@ -228,6 +235,56 @@
}
}
function isSlowOrMeteredConnection() {
const connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection;
if (!connection) {
return false;
}
if (connection.saveData === true) {
return true;
}
return ["slow-2g", "2g", "3g"].includes(connection.effectiveType);
}
function totalSelectedBytes(files) {
return files.reduce((sum, file) => sum + file.size, 0);
}
function confirmCellularUpload(files) {
const list = document.createElement("div");
list.className = "dialog-file-list";
files.forEach((file) => {
const icon = document.createElement("span");
icon.className = "svg-icon svg-icon-document dialog-file-icon";
icon.setAttribute("aria-hidden", "true");
const name = document.createElement("span");
name.className = "dialog-file-name";
name.textContent = file.name;
name.title = file.name;
const size = document.createElement("span");
size.className = "dialog-file-size";
size.textContent = window.Warpbox.formatBytes(file.size);
const row = document.createElement("div");
row.className = "dialog-file-row";
row.append(icon, name, size);
list.append(row);
});
const totalLabel = window.Warpbox.formatBytes(totalSelectedBytes(files));
const message = `You're on a slow or metered connection. You're about to upload ${files.length} file${files.length === 1 ? "" : "s"} (${totalLabel} total) — this could take a while or use up your data plan.`;
return window.Warpbox.confirmDialog(message, {
title: "Slow connection detected",
variant: "warning",
body: list,
confirmLabel: "Upload anyway",
cancelLabel: "Cancel",
});
}
function isShareTargetLaunch() {
const params = new URLSearchParams(window.location.search || "");
return params.has("share-target");