From 779f507304a7751e1492161d53c9ffecc38c1631 Mon Sep 17 00:00:00 2001 From: adabarbulescu Date: Sat, 18 Jul 2026 11:20:34 +0300 Subject: [PATCH] Fix reader email actions folder context --- static/js/emailLibrary.js | 45 +++++++++++++++++++++++++++------------ 1 file changed, 31 insertions(+), 14 deletions(-) diff --git a/static/js/emailLibrary.js b/static/js/emailLibrary.js index d691798ec0..eb15fa202d 100644 --- a/static/js/emailLibrary.js +++ b/static/js/emailLibrary.js @@ -3996,7 +3996,7 @@ async function _toggleCardPreview(card, em) { // Mark as read locally _syncEmailReadState(em.uid, true); _prefetchAdjacentEmails(card); - _stampReaderContext(reader, { ...em, ...data }, state._libFolder, state._libAccountId); + _stampReaderContext(reader, { ...em, ...data }, folderAtStart, accountAtStart); // Build the attachments wrap using the shared helper so the signature- // image filter (small inline PNGs/JPGs, Outlook image001 placeholders, @@ -6688,6 +6688,16 @@ function _showReaderMoreMenu(em, card, reader, anchor) { const _newTabIcon = ''; const _checkIcon = ''; const _translateIcon = ''; + const folder = reader?.dataset?.emailFolder || em?.folder || state._libFolder || 'INBOX'; + const account = reader?.dataset?.emailAccount || state._libAccountId || ''; + const accountQs = account ? `&account_id=${encodeURIComponent(account)}` : ''; + const emailUrl = (path) => `${API_BASE}${path}?folder=${encodeURIComponent(folder)}${accountQs}`; + const requireEmailOk = async (res) => { + let data = null; + try { data = await res.json(); } catch (_) {} + if (!res.ok || data?.success === false) throw new Error(data?.error || `HTTP ${res.status}`); + return data; + }; const closeAndRemove = async () => { // Pick the next neighbour BEFORE we re-render so we know which email to @@ -6721,7 +6731,6 @@ function _showReaderMoreMenu(em, card, reader, anchor) { label: 'Open in new tab', icon: _newTabIcon, action: async () => { - const folder = state._libFolder || 'INBOX'; await _openEmailAsTab(em, folder); }, }, @@ -6744,9 +6753,9 @@ function _showReaderMoreMenu(em, card, reader, anchor) { _syncEmailReadState(em.uid, newRead); try { if (newRead) { - await fetch(`${API_BASE}/api/email/mark-read/${em.uid}?folder=${encodeURIComponent(state._libFolder)}${_acct()}`, { method: 'POST' }); + await requireEmailOk(await fetch(emailUrl(`/api/email/mark-read/${em.uid}`), { method: 'POST' })); } else { - await fetch(`${API_BASE}/api/email/mark-unread/${em.uid}?folder=${encodeURIComponent(state._libFolder)}${_acct()}`, { method: 'POST' }); + await requireEmailOk(await fetch(emailUrl(`/api/email/mark-unread/${em.uid}`), { method: 'POST' })); } } catch (e) { console.error(e); } _renderGrid(); @@ -6764,7 +6773,7 @@ function _showReaderMoreMenu(em, card, reader, anchor) { em.is_flagged = next; _renderGrid(); try { - await fetch(`${API_BASE}/api/email/flag/${em.uid}?folder=${encodeURIComponent(state._libFolder)}${_acct()}&on=${next ? 'true' : 'false'}`, { method: 'POST' }); + await requireEmailOk(await fetch(`${emailUrl(`/api/email/flag/${em.uid}`)}&on=${next ? 'true' : 'false'}`, { method: 'POST' })); } catch (e) { // Roll back the optimistic flip if the server didn't take it. em.is_flagged = !next; @@ -6785,10 +6794,10 @@ function _showReaderMoreMenu(em, card, reader, anchor) { } try { if (newState) { - await fetch(`${API_BASE}/api/email/mark-answered/${em.uid}?folder=${encodeURIComponent(state._libFolder)}${_acct()}`, { method: 'POST' }); - await fetch(`${API_BASE}/api/email/mark-read/${em.uid}?folder=${encodeURIComponent(state._libFolder)}${_acct()}`, { method: 'POST' }); + await requireEmailOk(await fetch(emailUrl(`/api/email/mark-answered/${em.uid}`), { method: 'POST' })); + await requireEmailOk(await fetch(emailUrl(`/api/email/mark-read/${em.uid}`), { method: 'POST' })); } else { - await fetch(`${API_BASE}/api/email/clear-answered/${em.uid}?folder=${encodeURIComponent(state._libFolder)}${_acct()}`, { method: 'POST' }); + await requireEmailOk(await fetch(emailUrl(`/api/email/clear-answered/${em.uid}`), { method: 'POST' })); } } catch (e) { console.error('Failed to toggle done:', e); } _renderGrid(); @@ -6799,8 +6808,12 @@ function _showReaderMoreMenu(em, card, reader, anchor) { icon: _archIcon, action: async () => { try { - await fetch(`${API_BASE}/api/email/archive/${em.uid}?folder=${encodeURIComponent(state._libFolder)}${_acct()}`, { method: 'POST' }); - } catch (e) { console.error(e); } + await requireEmailOk(await fetch(emailUrl(`/api/email/archive/${em.uid}`), { method: 'POST' })); + } catch (e) { + console.error(e); + showToast('Failed to archive email'); + return; + } await closeAndRemove(); }, }, @@ -6840,8 +6853,12 @@ function _showReaderMoreMenu(em, card, reader, anchor) { icon: _spamIcon, action: async () => { try { - await fetch(`${API_BASE}/api/email/move/${em.uid}?folder=${encodeURIComponent(state._libFolder)}${_acct()}&dest=Junk`, { method: 'POST' }); - } catch (e) { console.error(e); } + await requireEmailOk(await fetch(`${emailUrl(`/api/email/move/${em.uid}`)}&dest=Junk`, { method: 'POST' })); + } catch (e) { + console.error(e); + showToast('Failed to move email'); + return; + } await closeAndRemove(); }, }, @@ -6852,7 +6869,7 @@ function _showReaderMoreMenu(em, card, reader, anchor) { const busy = _showEmailDeleteOverlay(card); await busy?.ready; try { - await fetch(`${API_BASE}/api/email/delete/${em.uid}?folder=${encodeURIComponent(state._libFolder)}${_acct()}`, { method: 'DELETE' }); + await requireEmailOk(await fetch(emailUrl(`/api/email/delete/${em.uid}`), { method: 'DELETE' })); } catch (e) { console.error(e); busy?.remove?.(); @@ -6877,7 +6894,7 @@ function _showReaderMoreMenu(em, card, reader, anchor) { const busy = _showEmailDeleteOverlay(card); await busy?.ready; try { - await fetch(`${API_BASE}/api/email/delete-permanent/${em.uid}?folder=${encodeURIComponent(state._libFolder)}${_acct()}`, { method: 'DELETE' }); + await requireEmailOk(await fetch(emailUrl(`/api/email/delete-permanent/${em.uid}`), { method: 'DELETE' })); } catch (e) { console.error(e); busy?.remove?.();