nothumanallowed 13.5.118 → 13.5.120
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/commands/ui.mjs +24 -0
- package/src/constants.mjs +1 -1
- package/src/services/email-db.mjs +3 -2
- package/src/services/email-imap.mjs +1 -0
- package/src/services/web-ui.mjs +88 -6
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nothumanallowed",
|
|
3
|
-
"version": "13.5.
|
|
3
|
+
"version": "13.5.120",
|
|
4
4
|
"description": "NotHumanAllowed — 38 AI agents, 80 tools, Studio (visual agentic workflows). Email, calendar, browser automation, screen capture, canvas, cron/heartbeat, Alexandria E2E messaging, GitHub, Notion, Slack, voice chat, free AI (Liara), 28 languages. Zero-dependency CLI.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
package/src/commands/ui.mjs
CHANGED
|
@@ -873,6 +873,30 @@ export async function cmdUI(args) {
|
|
|
873
873
|
logRequest(method, pathname, 200, Date.now() - start); return;
|
|
874
874
|
}
|
|
875
875
|
|
|
876
|
+
// GET /api/imap/unread-count — total unread across all active IMAP accounts
|
|
877
|
+
if (method === 'GET' && pathname === '/api/imap/unread-count') {
|
|
878
|
+
try {
|
|
879
|
+
const { listAccounts, getDb } = await import('../services/email-db.mjs');
|
|
880
|
+
const accounts = listAccounts();
|
|
881
|
+
const db = getDb();
|
|
882
|
+
let total = 0;
|
|
883
|
+
for (const acc of accounts) {
|
|
884
|
+
const row = db.prepare(`
|
|
885
|
+
SELECT COUNT(*) as n FROM email_messages m
|
|
886
|
+
JOIN email_message_labels eml ON eml.message_id = m.id
|
|
887
|
+
JOIN email_labels l ON l.id = eml.label_id
|
|
888
|
+
LEFT JOIN email_message_state s ON s.message_id = m.id
|
|
889
|
+
WHERE m.account_id = ? AND l.system_type = 'inbox'
|
|
890
|
+
AND COALESCE(s.is_read, 0) = 0
|
|
891
|
+
AND m.permanently_deleted = 0
|
|
892
|
+
`).get(acc.id);
|
|
893
|
+
total += row?.n || 0;
|
|
894
|
+
}
|
|
895
|
+
sendJSON(res, 200, { unread: total });
|
|
896
|
+
} catch (e) { sendJSON(res, 500, { error: e.message }); }
|
|
897
|
+
logRequest(method, pathname, 200, Date.now() - start); return;
|
|
898
|
+
}
|
|
899
|
+
|
|
876
900
|
// POST /api/imap/mark-read
|
|
877
901
|
if (method === 'POST' && pathname === '/api/imap/mark-read') {
|
|
878
902
|
try {
|
package/src/constants.mjs
CHANGED
|
@@ -5,7 +5,7 @@ import { fileURLToPath } from 'url';
|
|
|
5
5
|
const __filename = fileURLToPath(import.meta.url);
|
|
6
6
|
const __dirname = path.dirname(__filename);
|
|
7
7
|
|
|
8
|
-
export const VERSION = '13.5.
|
|
8
|
+
export const VERSION = '13.5.120';
|
|
9
9
|
export const BASE_URL = 'https://nothumanallowed.com/cli';
|
|
10
10
|
export const API_BASE = 'https://nothumanallowed.com/api/v1';
|
|
11
11
|
|
|
@@ -448,8 +448,9 @@ export function insertMessage(data) {
|
|
|
448
448
|
data.has_attachments ? 1 : 0, data.content_hash || null,
|
|
449
449
|
data.internal_date, data.source || 'imap'
|
|
450
450
|
);
|
|
451
|
-
// Init read state
|
|
452
|
-
|
|
451
|
+
// Init read state from IMAP \Seen flag
|
|
452
|
+
const isRead = data.imap_seen ? 1 : 0;
|
|
453
|
+
db.prepare('INSERT OR IGNORE INTO email_message_state (message_id, is_read, is_starred) VALUES (?, ?, 0)').run(id, isRead);
|
|
453
454
|
return id;
|
|
454
455
|
}
|
|
455
456
|
|
|
@@ -296,6 +296,7 @@ export async function syncFolder(accountId, folderPath, fullResync, limitMessage
|
|
|
296
296
|
has_attachments: attachments.length > 0,
|
|
297
297
|
content_hash: hash,
|
|
298
298
|
internal_date: hdr.internalDate,
|
|
299
|
+
imap_seen: hdr.flags?.has('\\Seen') ?? false,
|
|
299
300
|
source: 'imap',
|
|
300
301
|
});
|
|
301
302
|
|
package/src/services/web-ui.mjs
CHANGED
|
@@ -295,11 +295,27 @@ function loadDash(){
|
|
|
295
295
|
}
|
|
296
296
|
function loadAgents(){return apiGet('/api/agents').then(function(r){agentsList=(r&&r.agents)||[]})}
|
|
297
297
|
function updateBadges(){
|
|
298
|
-
var
|
|
299
|
-
var
|
|
300
|
-
if(eb){eb.textContent=ue;eb.style.display=ue>0?'':'none'}
|
|
298
|
+
var tb=document.getElementById('taskBadge'),cb=document.getElementById('calBadge');
|
|
299
|
+
var ut=dash.tasks.filter(function(t){return t.status!=='done'}).length,uc=dash.events.length;
|
|
301
300
|
if(tb){tb.textContent=ut;tb.style.display=ut>0?'':'none'}
|
|
302
301
|
if(cb){cb.textContent=uc;cb.style.display=uc>0?'':'none'}
|
|
302
|
+
updateEmailBadge();
|
|
303
|
+
}
|
|
304
|
+
function updateEmailBadge(){
|
|
305
|
+
var eb=document.getElementById('emailBadge');
|
|
306
|
+
if(!eb)return;
|
|
307
|
+
// Try IMAP unread first; fall back to Google dash count
|
|
308
|
+
apiGet('/api/imap/unread-count').then(function(r){
|
|
309
|
+
var imapUnread=r.unread||0;
|
|
310
|
+
var googleUnread=dash.emails?dash.emails.filter(function(e){return e.isUnread}).length:0;
|
|
311
|
+
var total=imapUnread+googleUnread;
|
|
312
|
+
eb.textContent=total;
|
|
313
|
+
eb.style.display=total>0?'':'none';
|
|
314
|
+
}).catch(function(){
|
|
315
|
+
var ue=dash.emails?dash.emails.filter(function(e){return e.isUnread}).length:0;
|
|
316
|
+
eb.textContent=ue;
|
|
317
|
+
eb.style.display=ue>0?'':'none';
|
|
318
|
+
});
|
|
303
319
|
}
|
|
304
320
|
|
|
305
321
|
// ---- HELPERS ----
|
|
@@ -1397,7 +1413,7 @@ function emailOpenMessage(id) {
|
|
|
1397
1413
|
emailRenderReadingPane(pane, r.message);
|
|
1398
1414
|
// Update read state in local list
|
|
1399
1415
|
var msg = emailState.messages.find(function(m) { return m.id === id; });
|
|
1400
|
-
if (msg) msg.is_read = true;
|
|
1416
|
+
if (msg && !msg.is_read) { msg.is_read = true; updateEmailBadge(); }
|
|
1401
1417
|
emailRenderMessageList();
|
|
1402
1418
|
}).catch(function(e) {
|
|
1403
1419
|
pane.innerHTML = '<div style="padding:20px;color:var(--red);font-size:12px">' + esc(e.message) + '</div>';
|
|
@@ -1463,18 +1479,83 @@ function emailRenderReadingPane(pane, m) {
|
|
|
1463
1479
|
pane.innerHTML = '<div style="display:flex;flex-direction:column;height:100%">' + h + '</div>';
|
|
1464
1480
|
}
|
|
1465
1481
|
|
|
1482
|
+
var EMAIL_TEMPLATES = [
|
|
1483
|
+
{
|
|
1484
|
+
id: 'promo_product',
|
|
1485
|
+
name: 'Promozione prodotto',
|
|
1486
|
+
subject: 'Scopri la nostra offerta su [PRODOTTO]',
|
|
1487
|
+
html: '<table width="100%" cellpadding="0" cellspacing="0" style="max-width:600px;margin:0 auto;font-family:Arial,sans-serif"><tr><td style="background:#1a1a2e;padding:32px 40px;text-align:center"><h1 style="color:#00ff9d;margin:0;font-size:26px;letter-spacing:-0.5px">[AZIENDA]</h1></td></tr><tr><td style="padding:40px;background:#ffffff"><h2 style="color:#1a1a2e;font-size:22px;margin:0 0 16px">[TITOLO OFFERTA]</h2><p style="color:#444;font-size:15px;line-height:1.7;margin:0 0 24px">[DESCRIZIONE PRODOTTO/SERVIZIO]</p><p style="color:#444;font-size:15px;line-height:1.7;margin:0 0 32px">[DETTAGLIO BENEFICI O SPECIFICHE]</p><table cellpadding="0" cellspacing="0"><tr><td style="background:#00ff9d;border-radius:6px;padding:14px 32px"><a href="[LINK_CTA]" style="color:#1a1a2e;font-weight:700;font-size:15px;text-decoration:none">[TESTO CTA]</a></td></tr></table></td></tr><tr><td style="padding:24px 40px;background:#f5f5f5;text-align:center"><p style="color:#888;font-size:12px;margin:0">[AZIENDA] • [INDIRIZZO] • <a href="mailto:[EMAIL]" style="color:#888">[EMAIL]</a></p><p style="color:#bbb;font-size:11px;margin:8px 0 0"><a href="[UNSUBSCRIBE_LINK]" style="color:#bbb">Disiscriviti</a></p></td></tr></table>',
|
|
1488
|
+
},
|
|
1489
|
+
{
|
|
1490
|
+
id: 'newsletter',
|
|
1491
|
+
name: 'Newsletter mensile',
|
|
1492
|
+
subject: '[AZIENDA] Newsletter — [MESE] [ANNO]',
|
|
1493
|
+
html: '<table width="100%" cellpadding="0" cellspacing="0" style="max-width:600px;margin:0 auto;font-family:Arial,sans-serif"><tr><td style="background:#0f0f1a;padding:28px 40px;border-bottom:3px solid #00ff9d"><h1 style="color:#ffffff;margin:0;font-size:22px">[AZIENDA]</h1><p style="color:#00ff9d;margin:6px 0 0;font-size:13px">Newsletter [MESE] [ANNO]</p></td></tr><tr><td style="padding:36px 40px;background:#ffffff"><h2 style="color:#1a1a2e;font-size:20px;margin:0 0 12px">[TITOLO PRINCIPALE]</h2><p style="color:#555;font-size:14px;line-height:1.8;margin:0 0 28px">[TESTO PRINCIPALE — racconta la novità principale del mese]</p><hr style="border:none;border-top:1px solid #eee;margin:0 0 28px"><h3 style="color:#1a1a2e;font-size:16px;margin:0 0 10px">[TITOLO SEZIONE 2]</h3><p style="color:#555;font-size:14px;line-height:1.8;margin:0 0 28px">[TESTO SEZIONE 2]</p><hr style="border:none;border-top:1px solid #eee;margin:0 0 28px"><h3 style="color:#1a1a2e;font-size:16px;margin:0 0 10px">[TITOLO SEZIONE 3]</h3><p style="color:#555;font-size:14px;line-height:1.8;margin:0 0 28px">[TESTO SEZIONE 3]</p><table cellpadding="0" cellspacing="0"><tr><td style="background:#1a1a2e;border-radius:6px;padding:12px 28px"><a href="[LINK]" style="color:#00ff9d;font-weight:700;font-size:14px;text-decoration:none">Leggi di più →</a></td></tr></table></td></tr><tr><td style="padding:20px 40px;background:#f9f9f9;text-align:center"><p style="color:#999;font-size:12px;margin:0">© [ANNO] [AZIENDA] • <a href="[UNSUBSCRIBE_LINK]" style="color:#999">Disiscriviti</a></p></td></tr></table>',
|
|
1494
|
+
},
|
|
1495
|
+
{
|
|
1496
|
+
id: 'follow_up',
|
|
1497
|
+
name: 'Follow-up commerciale',
|
|
1498
|
+
subject: 'Seguito alla nostra conversazione — [ARGOMENTO]',
|
|
1499
|
+
html: '<table width="100%" cellpadding="0" cellspacing="0" style="max-width:580px;margin:0 auto;font-family:Arial,sans-serif"><tr><td style="padding:40px"><p style="color:#333;font-size:15px;line-height:1.7;margin:0 0 16px">Gentile [NOME],</p><p style="color:#333;font-size:15px;line-height:1.7;margin:0 0 16px">la contatto in seguito a [CONTESTO: fiera / chiamata / incontro del GIORNO].</p><p style="color:#333;font-size:15px;line-height:1.7;margin:0 0 16px">[CORPO PRINCIPALE: riassumi la proposta, il valore offerto, eventuali prossimi passi]</p><p style="color:#333;font-size:15px;line-height:1.7;margin:0 0 32px">[CHIUSURA: proposta di call / richiesta feedback / disponibilità a incontro]</p><p style="color:#333;font-size:15px;line-height:1.7;margin:0 0 4px">Cordiali saluti,</p><p style="color:#1a1a2e;font-size:15px;font-weight:700;margin:0">[NOME MITTENTE]</p><p style="color:#888;font-size:13px;margin:4px 0 0">[RUOLO] • [AZIENDA] • [TELEFONO]</p></td></tr></table>',
|
|
1500
|
+
},
|
|
1501
|
+
{
|
|
1502
|
+
id: 'offerta',
|
|
1503
|
+
name: 'Invio offerta / preventivo',
|
|
1504
|
+
subject: 'Offerta [NUMERO] — [OGGETTO FORNITURA]',
|
|
1505
|
+
html: '<table width="100%" cellpadding="0" cellspacing="0" style="max-width:600px;margin:0 auto;font-family:Arial,sans-serif"><tr><td style="background:#1a1a2e;padding:24px 40px"><h1 style="color:#00ff9d;margin:0;font-size:20px">[AZIENDA]</h1><p style="color:#aaa;margin:4px 0 0;font-size:12px">Offerta n. [NUMERO] del [DATA]</p></td></tr><tr><td style="padding:36px 40px;background:#ffffff"><p style="color:#333;font-size:15px;line-height:1.7;margin:0 0 16px">Gentile [NOME],</p><p style="color:#333;font-size:15px;line-height:1.7;margin:0 0 24px">in risposta alla Vostra richiesta, siamo lieti di sottoporre la seguente offerta:</p><table width="100%" cellpadding="10" cellspacing="0" style="border-collapse:collapse;margin-bottom:24px"><tr style="background:#f0f0f0"><th style="text-align:left;font-size:13px;color:#333;border-bottom:2px solid #ddd">Descrizione</th><th style="text-align:right;font-size:13px;color:#333;border-bottom:2px solid #ddd">Qtà</th><th style="text-align:right;font-size:13px;color:#333;border-bottom:2px solid #ddd">Prezzo unit.</th><th style="text-align:right;font-size:13px;color:#333;border-bottom:2px solid #ddd">Totale</th></tr><tr><td style="font-size:13px;color:#444;border-bottom:1px solid #eee">[ARTICOLO 1]</td><td style="text-align:right;font-size:13px;color:#444;border-bottom:1px solid #eee">[QT]</td><td style="text-align:right;font-size:13px;color:#444;border-bottom:1px solid #eee">€ [PREZZO]</td><td style="text-align:right;font-size:13px;color:#444;border-bottom:1px solid #eee">€ [TOT]</td></tr><tr><td style="font-size:13px;color:#444;border-bottom:1px solid #eee">[ARTICOLO 2]</td><td style="text-align:right;font-size:13px;color:#444;border-bottom:1px solid #eee">[QT]</td><td style="text-align:right;font-size:13px;color:#444;border-bottom:1px solid #eee">€ [PREZZO]</td><td style="text-align:right;font-size:13px;color:#444;border-bottom:1px solid #eee">€ [TOT]</td></tr><tr style="background:#f9f9f9"><td colspan="3" style="text-align:right;font-weight:700;font-size:14px;color:#1a1a2e;padding-top:12px">Totale IVA esclusa</td><td style="text-align:right;font-weight:700;font-size:14px;color:#1a1a2e;padding-top:12px">€ [TOTALE]</td></tr></table><p style="color:#555;font-size:13px;line-height:1.7;margin:0 0 8px"><strong>Condizioni di pagamento:</strong> [PAGAMENTO]</p><p style="color:#555;font-size:13px;line-height:1.7;margin:0 0 8px"><strong>Tempi di consegna:</strong> [CONSEGNA]</p><p style="color:#555;font-size:13px;line-height:1.7;margin:0 0 24px"><strong>Validità offerta:</strong> [VALIDITA]</p><p style="color:#333;font-size:14px;line-height:1.7;margin:0 0 4px">Resto a disposizione per qualsiasi chiarimento.</p><p style="color:#333;font-size:14px;line-height:1.7;margin:0 0 4px">Cordiali saluti,</p><p style="color:#1a1a2e;font-size:14px;font-weight:700;margin:0">[NOME MITTENTE]</p><p style="color:#888;font-size:12px;margin:4px 0 0">[AZIENDA] • [EMAIL] • [TELEFONO]</p></td></tr></table>',
|
|
1506
|
+
},
|
|
1507
|
+
{
|
|
1508
|
+
id: 'evento',
|
|
1509
|
+
name: 'Invito evento / webinar',
|
|
1510
|
+
subject: 'Sei invitato: [NOME EVENTO] — [DATA]',
|
|
1511
|
+
html: '<table width="100%" cellpadding="0" cellspacing="0" style="max-width:600px;margin:0 auto;font-family:Arial,sans-serif"><tr><td style="background:linear-gradient(135deg,#0f0f1a,#1a2a1a);padding:48px 40px;text-align:center"><h1 style="color:#00ff9d;margin:0 0 8px;font-size:28px;letter-spacing:-0.5px">[NOME EVENTO]</h1><p style="color:#aaffcc;margin:0;font-size:16px">[DATA] • [ORA] • [LUOGO / Online]</p></td></tr><tr><td style="padding:40px;background:#ffffff;text-align:center"><p style="color:#444;font-size:15px;line-height:1.8;max-width:460px;margin:0 auto 28px">[DESCRIZIONE EVENTO: di cosa si tratta, a chi è rivolto, perché non perderselo]</p><p style="color:#555;font-size:14px;line-height:1.8;max-width:460px;margin:0 auto 32px">[AGENDA O PUNTI CHIAVE]</p><table cellpadding="0" cellspacing="0" style="margin:0 auto 32px"><tr><td style="background:#00ff9d;border-radius:8px;padding:14px 40px"><a href="[LINK_REGISTRAZIONE]" style="color:#0f0f1a;font-weight:700;font-size:15px;text-decoration:none">Registrati ora →</a></td></tr></table><p style="color:#999;font-size:12px;margin:0">Posti limitati • Registrazione gratuita</p></td></tr><tr><td style="padding:20px 40px;background:#f5f5f5;text-align:center"><p style="color:#bbb;font-size:11px;margin:0">[AZIENDA] • <a href="[UNSUBSCRIBE_LINK]" style="color:#bbb">Disiscriviti</a></p></td></tr></table>',
|
|
1512
|
+
},
|
|
1513
|
+
{
|
|
1514
|
+
id: 'ringraziamento',
|
|
1515
|
+
name: 'Ringraziamento cliente',
|
|
1516
|
+
subject: 'Grazie per la fiducia, [NOME]',
|
|
1517
|
+
html: '<table width="100%" cellpadding="0" cellspacing="0" style="max-width:580px;margin:0 auto;font-family:Arial,sans-serif"><tr><td style="background:#0f0f1a;padding:32px 40px;text-align:center"><p style="color:#00ff9d;font-size:36px;margin:0">🙏</p><h1 style="color:#ffffff;font-size:22px;margin:8px 0 0">Grazie, [NOME]!</h1></td></tr><tr><td style="padding:40px;background:#ffffff"><p style="color:#333;font-size:15px;line-height:1.8;margin:0 0 16px">Volevamo ringraziarti personalmente per [MOTIVO: il tuo acquisto / la tua fiducia / anni di collaborazione].</p><p style="color:#333;font-size:15px;line-height:1.8;margin:0 0 16px">[MESSAGGIO PERSONALE: cosa significa per noi, cosa ci impegniamo a fare, cosa offriamo come segno di riconoscimento]</p><p style="color:#333;font-size:15px;line-height:1.8;margin:0 0 32px">[CHIUSURA: invito a restare in contatto, disponibilità]</p><p style="color:#333;font-size:15px;margin:0 0 4px">Con stima,</p><p style="color:#1a1a2e;font-size:15px;font-weight:700;margin:0">[NOME MITTENTE]</p><p style="color:#888;font-size:13px;margin:4px 0 0">[RUOLO] • [AZIENDA]</p></td></tr></table>',
|
|
1518
|
+
},
|
|
1519
|
+
];
|
|
1520
|
+
|
|
1521
|
+
function emailLoadTemplate(idx) {
|
|
1522
|
+
var t = EMAIL_TEMPLATES[idx];
|
|
1523
|
+
if (!t) return;
|
|
1524
|
+
var subj = document.getElementById('compSubject');
|
|
1525
|
+
if (subj && !subj.value) subj.value = t.subject;
|
|
1526
|
+
if (emailState.quillEditor) {
|
|
1527
|
+
emailState.quillEditor.clipboard.dangerouslyPasteHTML(t.html);
|
|
1528
|
+
}
|
|
1529
|
+
var dd = document.getElementById('compTemplateDrop');
|
|
1530
|
+
if (dd) dd.style.display = 'none';
|
|
1531
|
+
}
|
|
1532
|
+
|
|
1533
|
+
function emailToggleTemplates() {
|
|
1534
|
+
var dd = document.getElementById('compTemplateDrop');
|
|
1535
|
+
if (!dd) return;
|
|
1536
|
+
dd.style.display = dd.style.display === 'none' ? 'block' : 'none';
|
|
1537
|
+
}
|
|
1538
|
+
|
|
1466
1539
|
function emailOpenCompose(opts) {
|
|
1467
1540
|
var pane = document.getElementById('emailPane');
|
|
1468
1541
|
if (!pane) return;
|
|
1469
1542
|
opts = opts || {};
|
|
1470
1543
|
|
|
1471
|
-
var h = '<div style="display:flex;flex-direction:column;height:100%;padding:14px;gap:
|
|
1544
|
+
var h = '<div style="display:flex;flex-direction:column;height:100%;padding:14px;gap:8px">';
|
|
1472
1545
|
h += '<div style="font-size:13px;font-weight:700;color:var(--bright);border-bottom:1px solid var(--border);padding-bottom:8px">Compose</div>';
|
|
1473
1546
|
h += '<input id="compTo" type="text" placeholder="To" value="' + esc(opts.to || '') + '" style="padding:7px 10px;font-size:12px;background:var(--bg);color:var(--fg);border:1px solid var(--border2);border-radius:5px">';
|
|
1474
1547
|
h += '<input id="compCc" type="text" placeholder="Cc" style="padding:7px 10px;font-size:12px;background:var(--bg);color:var(--fg);border:1px solid var(--border2);border-radius:5px">';
|
|
1475
1548
|
h += '<input id="compSubject" type="text" placeholder="Subject" value="' + esc(opts.subject || '') + '" style="padding:7px 10px;font-size:12px;background:var(--bg);color:var(--fg);border:1px solid var(--border2);border-radius:5px">';
|
|
1476
1549
|
h += '<input type="hidden" id="compInReplyTo" value="' + esc(opts.inReplyTo || '') + '">';
|
|
1477
1550
|
h += '<input type="hidden" id="compReplyToId" value="' + esc(opts.replyTo || '') + '">';
|
|
1551
|
+
// Template picker
|
|
1552
|
+
h += '<div style="position:relative">';
|
|
1553
|
+
h += '<button onclick="emailToggleTemplates()" style="padding:5px 12px;font-size:11px;background:var(--bg);color:var(--cyan);border:1px solid var(--cyan);border-radius:5px;cursor:pointer">📄 Template marketing</button>';
|
|
1554
|
+
h += '<div id="compTemplateDrop" style="display:none;position:absolute;top:100%;left:0;z-index:200;background:var(--bg2);border:1px solid var(--border);border-radius:6px;min-width:240px;padding:4px 0;margin-top:4px;box-shadow:0 4px 16px rgba(0,0,0,0.3)">';
|
|
1555
|
+
for (var ti = 0; ti < EMAIL_TEMPLATES.length; ti++) {
|
|
1556
|
+
h += '<div class="tpl-item" onclick="emailLoadTemplate(' + ti + ')" style="padding:9px 16px;font-size:12px;cursor:pointer;color:var(--fg);border-bottom:1px solid var(--border)"><strong>' + esc(EMAIL_TEMPLATES[ti].name) + '</strong><div style="font-size:10px;color:var(--dim);margin-top:2px">' + esc(EMAIL_TEMPLATES[ti].subject.slice(0, 50)) + '</div></div>';
|
|
1557
|
+
}
|
|
1558
|
+
h += '</div></div>';
|
|
1478
1559
|
// Quill editor container
|
|
1479
1560
|
h += '<div id="quillContainer" style="flex:1;min-height:200px;background:#fff;border-radius:5px;overflow:auto"></div>';
|
|
1480
1561
|
// Toolbar
|
|
@@ -1624,7 +1705,8 @@ function emailSyncCurrent() {
|
|
|
1624
1705
|
if (!emailState.accountId || emailState.accountType !== 'imap') return;
|
|
1625
1706
|
apiPost('/api/imap/sync', { accountId: emailState.accountId }).then(function() {
|
|
1626
1707
|
showToast('success', 'Sync', 'Sync started — messages will appear shortly');
|
|
1627
|
-
setTimeout(function() { emailLoadMessages(); }, 5000);
|
|
1708
|
+
setTimeout(function() { emailLoadMessages(); updateEmailBadge(); }, 5000);
|
|
1709
|
+
setTimeout(function() { emailLoadMessages(); updateEmailBadge(); }, 15000);
|
|
1628
1710
|
});
|
|
1629
1711
|
}
|
|
1630
1712
|
|