mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-07-08 11:56:59 +00:00
Allow stalled chat uploads to be cancelled
This commit is contained in:
@@ -292,6 +292,9 @@ import { wireArrowUpRecall, getLastUserMessageFromChatHistory } from './composer
|
||||
|
||||
// If currently streaming, stop it
|
||||
if (isStreaming) {
|
||||
if (fileHandlerModule.isUploading && fileHandlerModule.isUploading()) {
|
||||
fileHandlerModule.cancelUpload && fileHandlerModule.cancelUpload();
|
||||
}
|
||||
// Cancel server-side research if in progress
|
||||
const _cancelSid = sessionModule.getCurrentSessionId();
|
||||
if (_cancelSid && _researchingStreamIds.has(_cancelSid)) {
|
||||
@@ -687,6 +690,15 @@ import { wireArrowUpRecall, getLastUserMessageFromChatHistory } from './composer
|
||||
} catch(e) {
|
||||
console.error('upload failed', e);
|
||||
}
|
||||
if (_pendingAttachInfo && !ids.length && !(_pendingRegenAttachments && _pendingRegenAttachments.length)) {
|
||||
if (_userMsgEl && _userMsgEl.parentNode) _userMsgEl.remove();
|
||||
if (fileHandlerModule.wasLastUploadCancelled && !fileHandlerModule.wasLastUploadCancelled()) {
|
||||
uiModule.showError && uiModule.showError('Upload failed. Attachment kept so you can retry.');
|
||||
}
|
||||
updateSubmitButton('idle', submitBtn);
|
||||
_releaseSendFlag();
|
||||
return;
|
||||
}
|
||||
|
||||
// Carry over the original message's file-ids on a regenerate so the new
|
||||
// send still references the same photos / docs (and picks up the user's
|
||||
|
||||
@@ -15,6 +15,9 @@ let uploaded = [];
|
||||
let _lastUploadedMeta = [];
|
||||
let API_BASE = '';
|
||||
let _uploadSpinners = [];
|
||||
let _uploadAbortCtrl = null;
|
||||
let _uploading = false;
|
||||
let _lastUploadCancelled = false;
|
||||
const _previewUrls = new WeakMap();
|
||||
|
||||
const MAX_FILES = 10;
|
||||
@@ -130,6 +133,7 @@ function _createChip(f, idx) {
|
||||
* Remove a pending file by index
|
||||
*/
|
||||
export function removePending(idx) {
|
||||
if (_uploading) cancelUpload();
|
||||
_revokePreviewUrl(pendingFiles[idx]);
|
||||
pendingFiles.splice(idx, 1);
|
||||
renderAttachStrip();
|
||||
@@ -140,6 +144,7 @@ export function removePending(idx) {
|
||||
*/
|
||||
export async function uploadPending() {
|
||||
if (pendingFiles.length === 0) return [];
|
||||
_lastUploadCancelled = false;
|
||||
|
||||
// The message bubble is shown immediately, but the upload can take a moment —
|
||||
// dim the chips and overlay a whirlpool so it's clear the files are still
|
||||
@@ -164,11 +169,19 @@ export async function uploadPending() {
|
||||
|
||||
const fd = new FormData();
|
||||
pendingFiles.forEach(f => fd.append('files', f, f.name || 'paste.png'));
|
||||
_uploadAbortCtrl = new AbortController();
|
||||
_uploading = true;
|
||||
const timeoutId = setTimeout(() => {
|
||||
if (_uploadAbortCtrl && !_uploadAbortCtrl.signal.aborted) {
|
||||
try { _uploadAbortCtrl.abort(); } catch (_) {}
|
||||
}
|
||||
}, 120000);
|
||||
|
||||
try {
|
||||
const res = await fetch(`${API_BASE}/api/upload`, {
|
||||
method: 'POST',
|
||||
body: fd
|
||||
body: fd,
|
||||
signal: _uploadAbortCtrl.signal,
|
||||
});
|
||||
if (!res.ok) {
|
||||
// Surface the failure instead of swallowing it. Previously a non-OK
|
||||
@@ -193,7 +206,18 @@ export async function uploadPending() {
|
||||
// returned shape as `ids` for backward-compatibility with existing call sites.
|
||||
_lastUploadedMeta = uploaded;
|
||||
return uploaded.map(x => x.id);
|
||||
} catch (e) {
|
||||
if (e && e.name === 'AbortError') {
|
||||
_lastUploadCancelled = true;
|
||||
_showToast('Upload cancelled');
|
||||
return [];
|
||||
}
|
||||
_showToast('Upload failed: ' + (e?.message || 'network error'));
|
||||
return [];
|
||||
} finally {
|
||||
clearTimeout(timeoutId);
|
||||
_uploading = false;
|
||||
_uploadAbortCtrl = null;
|
||||
_uploadSpinners.forEach(sp => { try { sp.stop && sp.stop(); } catch (_) {} });
|
||||
_uploadSpinners = [];
|
||||
if (strip) strip.classList.remove('attach-uploading');
|
||||
@@ -266,6 +290,7 @@ export function getPendingInfo() {
|
||||
* Clear all pending files
|
||||
*/
|
||||
export function clearPending() {
|
||||
if (_uploading) cancelUpload();
|
||||
pendingFiles.forEach(_revokePreviewUrl);
|
||||
pendingFiles = [];
|
||||
renderAttachStrip();
|
||||
@@ -276,6 +301,21 @@ export function getLastUploadedMeta() {
|
||||
return _lastUploadedMeta;
|
||||
}
|
||||
|
||||
export function isUploading() {
|
||||
return _uploading;
|
||||
}
|
||||
|
||||
export function wasLastUploadCancelled() {
|
||||
return _lastUploadCancelled;
|
||||
}
|
||||
|
||||
export function cancelUpload() {
|
||||
_lastUploadCancelled = true;
|
||||
if (_uploadAbortCtrl && !_uploadAbortCtrl.signal.aborted) {
|
||||
try { _uploadAbortCtrl.abort(); } catch (_) {}
|
||||
}
|
||||
}
|
||||
|
||||
var escapeHtml = uiModule.esc;
|
||||
|
||||
const fileHandlerModule = {
|
||||
@@ -290,6 +330,9 @@ const fileHandlerModule = {
|
||||
getPendingRaw,
|
||||
clearPending,
|
||||
getLastUploadedMeta,
|
||||
isUploading,
|
||||
wasLastUploadCancelled,
|
||||
cancelUpload,
|
||||
};
|
||||
|
||||
export default fileHandlerModule;
|
||||
|
||||
Reference in New Issue
Block a user