Outbox: add SEND button for queued drafts (compose previously had no way to actually send), fix VIEW showing body via list endpoint that omits it

This commit is contained in:
root
2026-07-07 08:58:20 -05:00
parent 24b96e809c
commit 5ff4f3e311
+31 -5
View File
@@ -837,6 +837,24 @@ if ($action) {
$raw = curl_exec($ch); curl_close($ch); $raw = curl_exec($ch); curl_close($ch);
j(json_decode($raw, true) ?: ['error'=>'failed']); j(json_decode($raw, true) ?: ['error'=>'failed']);
// Added 2026-07-07: fetch a single outbox item WITH its body — outbox_list
// deliberately omits body for list-view performance, but VIEW needs the full text.
case 'outbox_get':
$id = (int)($_GET['id'] ?? 0); if (!$id) bad('Missing id');
$ch = curl_init('http://127.0.0.1:7474/comms/sent/' . $id);
curl_setopt_array($ch, [CURLOPT_RETURNTRANSFER=>true, CURLOPT_TIMEOUT=>5]);
$raw = curl_exec($ch); curl_close($ch);
j(json_decode($raw, true) ?: ['error'=>'failed']);
// Added 2026-07-07: closes the "compose creates a draft but nothing can ever
// send it" gap — dispatches a queued draft through the real send path.
case 'outbox_send':
$id = (int)($_GET['id'] ?? 0); if (!$id) bad('Missing id');
$ch = curl_init('http://127.0.0.1:7474/comms/sent/' . $id . '/send');
curl_setopt_array($ch, [CURLOPT_RETURNTRANSFER=>true, CURLOPT_TIMEOUT=>30, CURLOPT_POST=>true, CURLOPT_POSTFIELDS=>'']);
$raw = curl_exec($ch); curl_close($ch);
j(json_decode($raw, true) ?: ['error'=>'failed']);
case 'send_reply': case 'send_reply':
$id = (int)($_GET['id'] ?? 0); if (!$id) bad('Missing triage id'); $id = (int)($_GET['id'] ?? 0); if (!$id) bad('Missing triage id');
$content = $_GET['content'] ?? ''; $content = $_GET['content'] ?? '';
@@ -4370,6 +4388,7 @@ async function loadOutbox() {
<td style="font-size:0.6rem;color:var(--dim)">${m.account||'gmail'}</td> <td style="font-size:0.6rem;color:var(--dim)">${m.account||'gmail'}</td>
<td style="font-size:0.6rem;color:var(--dim)">${ts}</td> <td style="font-size:0.6rem;color:var(--dim)">${ts}</td>
<td style="white-space:nowrap"> <td style="white-space:nowrap">
${sc==='queued' ? `<button class="btn btn-xs btn-green" onclick="outboxSend(${m.id})">SEND</button>` : ''}
<button class="btn btn-xs" onclick="outboxViewBody(${m.id})">VIEW</button> <button class="btn btn-xs" onclick="outboxViewBody(${m.id})">VIEW</button>
<button class="btn btn-xs btn-red" onclick="outboxDelete(${m.id})">DEL</button> <button class="btn btn-xs btn-red" onclick="outboxDelete(${m.id})">DEL</button>
</td> </td>
@@ -4385,12 +4404,19 @@ async function outboxDelete(id) {
else toast('Delete failed: ' + (d.error||''), 'err'); else toast('Delete failed: ' + (d.error||''), 'err');
} }
// Added 2026-07-07: composing only ever created a queued draft — there was no
// button anywhere to actually send one. This closes that gap.
async function outboxSend(id) {
if (!confirm('Send this draft now?')) return;
const d = await api('outbox_send', {id});
if (d.success) { toast('Sent', 'ok'); loadOutbox(); }
else toast('Send failed: ' + (d.error||'unknown error'), 'err');
}
async function outboxViewBody(id) { async function outboxViewBody(id) {
const d = await api('outbox_list', {limit: 200}); const m = await api('outbox_get', {id});
const sent = Array.isArray(d) ? d : (d.sent || []); if (!m || m.error) { toast('Failed to load message', 'err'); return; }
const m = sent.find(x => x.id == id); openModal((m.status==='queued'?'DRAFT — ':'SENT MESSAGE — ') + esc(m.subject||''), `
if (!m) return;
openModal('SENT MESSAGE — ' + esc(m.subject||''), `
<div style="font-family:var(--mono);font-size:0.65rem;color:var(--text-dim);margin-bottom:8px">TO: ${esc(m.to_email||'')} · ACCOUNT: ${m.account||'gmail'}</div> <div style="font-family:var(--mono);font-size:0.65rem;color:var(--text-dim);margin-bottom:8px">TO: ${esc(m.to_email||'')} · ACCOUNT: ${m.account||'gmail'}</div>
<pre style="font-size:0.65rem;white-space:pre-wrap;max-height:300px;overflow-y:auto;background:rgba(0,212,255,0.03);border:1px solid var(--border);border-radius:3px;padding:8px">${esc(m.body||'(no body)')}</pre> <pre style="font-size:0.65rem;white-space:pre-wrap;max-height:300px;overflow-y:auto;background:rgba(0,212,255,0.03);border:1px solid var(--border);border-radius:3px;padding:8px">${esc(m.body||'(no body)')}</pre>
`, null, null); `, null, null);