polish canvas toolbar and upload stall handling
This commit is contained in:
parent
05b21707c1
commit
7ed0f08269
@ -10193,7 +10193,7 @@ export function ImageNode({
|
|||||||
createPortal(
|
createPortal(
|
||||||
<TooltipProvider delayDuration={200}>
|
<TooltipProvider delayDuration={200}>
|
||||||
<div
|
<div
|
||||||
className="fixed z-[9999] flex items-center gap-0.5 rounded-[24px] border border-slate-200 bg-white px-2 py-1.5 text-gray-800 shadow-[0_14px_38px_rgba(15,23,42,0.16)] dark:border-zinc-800 dark:bg-zinc-950 dark:text-zinc-100 dark:shadow-[0_16px_44px_rgba(0,0,0,0.45)]"
|
className="fixed z-[9999] flex items-center gap-0.5 rounded-[24px] border border-white/70 bg-white/82 px-2 py-1.5 text-gray-800 shadow-[0_18px_52px_rgba(15,23,42,0.20)] backdrop-blur-2xl before:pointer-events-none before:absolute before:inset-[-10px] before:-z-10 before:rounded-[32px] before:bg-white/35 before:shadow-[0_18px_64px_rgba(15,23,42,0.18)] before:backdrop-blur-2xl before:content-[''] supports-[backdrop-filter]:bg-white/72 dark:border-white/12 dark:bg-[#08090c]/72 dark:text-zinc-100 dark:shadow-[0_24px_72px_rgba(0,0,0,0.58)] dark:before:bg-black/35 dark:before:shadow-[0_24px_80px_rgba(0,0,0,0.62)] supports-[backdrop-filter]:dark:bg-[#08090c]/62"
|
||||||
onClick={(e) => e.stopPropagation()}
|
onClick={(e) => e.stopPropagation()}
|
||||||
onMouseDown={(e) => e.stopPropagation()}
|
onMouseDown={(e) => e.stopPropagation()}
|
||||||
onPointerDown={(e) => e.stopPropagation()}
|
onPointerDown={(e) => e.stopPropagation()}
|
||||||
|
|||||||
@ -7,6 +7,8 @@ const SERVER_UPLOAD_MAX_BYTES = 50 * 1024 * 1024;
|
|||||||
const DIRECT_UPLOAD_PART_CONCURRENCY = 4;
|
const DIRECT_UPLOAD_PART_CONCURRENCY = 4;
|
||||||
const DIRECT_UPLOAD_SUPPRESS_MS = 2 * 60 * 1000;
|
const DIRECT_UPLOAD_SUPPRESS_MS = 2 * 60 * 1000;
|
||||||
const CLIENT_UPLOAD_ID_FIELD = "clientUploadId";
|
const CLIENT_UPLOAD_ID_FIELD = "clientUploadId";
|
||||||
|
const XHR_UPLOAD_TOTAL_TIMEOUT_MS = 6 * 60 * 1000;
|
||||||
|
const XHR_UPLOAD_STALL_TIMEOUT_MS = 30 * 1000;
|
||||||
|
|
||||||
const RETRYABLE_UPLOAD_STATUSES = new Set([
|
const RETRYABLE_UPLOAD_STATUSES = new Set([
|
||||||
408,
|
408,
|
||||||
@ -388,6 +390,8 @@ function xhrUpload(
|
|||||||
options?: {
|
options?: {
|
||||||
signal?: AbortSignal;
|
signal?: AbortSignal;
|
||||||
onProgress?: (loaded: number, total: number) => void;
|
onProgress?: (loaded: number, total: number) => void;
|
||||||
|
timeoutMs?: number;
|
||||||
|
stallTimeoutMs?: number;
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
return new Promise<Response>((resolve, reject) => {
|
return new Promise<Response>((resolve, reject) => {
|
||||||
@ -398,10 +402,18 @@ function xhrUpload(
|
|||||||
|
|
||||||
const xhr = new XMLHttpRequest();
|
const xhr = new XMLHttpRequest();
|
||||||
let settled = false;
|
let settled = false;
|
||||||
|
let stallTimer: ReturnType<typeof setTimeout> | null = null;
|
||||||
|
|
||||||
|
const clearStallTimer = () => {
|
||||||
|
if (!stallTimer) return;
|
||||||
|
clearTimeout(stallTimer);
|
||||||
|
stallTimer = null;
|
||||||
|
};
|
||||||
|
|
||||||
const settle = (callback: () => void) => {
|
const settle = (callback: () => void) => {
|
||||||
if (settled) return;
|
if (settled) return;
|
||||||
settled = true;
|
settled = true;
|
||||||
|
clearStallTimer();
|
||||||
options?.signal?.removeEventListener("abort", onAbort);
|
options?.signal?.removeEventListener("abort", onAbort);
|
||||||
callback();
|
callback();
|
||||||
};
|
};
|
||||||
@ -412,12 +424,32 @@ function xhrUpload(
|
|||||||
};
|
};
|
||||||
|
|
||||||
xhr.open(init.method, url, true);
|
xhr.open(init.method, url, true);
|
||||||
|
xhr.timeout = options?.timeoutMs ?? XHR_UPLOAD_TOTAL_TIMEOUT_MS;
|
||||||
|
|
||||||
for (const [key, value] of normalizeXhrHeaders(init.headers)) {
|
for (const [key, value] of normalizeXhrHeaders(init.headers)) {
|
||||||
xhr.setRequestHeader(key, value);
|
xhr.setRequestHeader(key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const resetStallTimer = () => {
|
||||||
|
clearStallTimer();
|
||||||
|
if (settled) return;
|
||||||
|
|
||||||
|
const stallTimeoutMs =
|
||||||
|
options?.stallTimeoutMs ?? XHR_UPLOAD_STALL_TIMEOUT_MS;
|
||||||
|
if (stallTimeoutMs <= 0) return;
|
||||||
|
|
||||||
|
stallTimer = setTimeout(() => {
|
||||||
|
const error = new Error(
|
||||||
|
`Upload stalled for ${Math.round(stallTimeoutMs / 1000)}s`
|
||||||
|
);
|
||||||
|
error.name = "TimeoutError";
|
||||||
|
settle(() => reject(error));
|
||||||
|
xhr.abort();
|
||||||
|
}, stallTimeoutMs);
|
||||||
|
};
|
||||||
|
|
||||||
xhr.upload.onprogress = (event) => {
|
xhr.upload.onprogress = (event) => {
|
||||||
|
resetStallTimer();
|
||||||
const total = event.lengthComputable ? event.total : 0;
|
const total = event.lengthComputable ? event.total : 0;
|
||||||
options?.onProgress?.(event.loaded, total);
|
options?.onProgress?.(event.loaded, total);
|
||||||
};
|
};
|
||||||
@ -435,6 +467,7 @@ function xhrUpload(
|
|||||||
};
|
};
|
||||||
|
|
||||||
options?.signal?.addEventListener("abort", onAbort, { once: true });
|
options?.signal?.addEventListener("abort", onAbort, { once: true });
|
||||||
|
resetStallTimer();
|
||||||
xhr.send(init.body);
|
xhr.send(init.body);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user