fix(messages): PR #769 nits — server-side search, bare-email recipient, DE i18n

- Search now hits the backend (debounced) so results aren't truncated to the
  first loaded page: /received gains a `q` filter (sender/subject); the frontend
  passes the debounced term to every list query. The instant client-side filter
  stays for responsiveness.
- Reply/compose recipient extracts the bare address from a "Name <addr>" From
  header (extractEmail) — also used for the customer-lookup key.
- Added the full de + en `messages.*` and `email.customerMailbox.*` translation
  namespaces (were English inline-fallbacks only). Swiss-German spelling.
This commit is contained in:
Luca
2026-07-07 18:39:04 +02:00
parent bb235e72e5
commit 1e08a4fb15
5 changed files with 237 additions and 15 deletions
+4
View File
@@ -267,12 +267,16 @@ router.get('/received', adminAuth, requirePermission('email.view'), async (req,
const account = req.query.account ? String(req.query.account) : null;
// mailbox_state filter: no param → active (+ legacy NULL); else exact.
const state = ['archived', 'deleted'].includes(String(req.query.state)) ? String(req.query.state) : 'active';
// Optional full-table search (sender / subject) so results aren't truncated
// to the first page before matching.
const q = req.query.q ? String(req.query.q).trim().slice(0, 255) : '';
// 'accounting' matches legacy rows too (account_key was NULL before mig 154).
const applyAccount = (qb) => {
if (account === 'accounting') qb.where((b) => b.where('account_key', 'accounting').orWhereNull('account_key'));
else if (account) qb.where('account_key', account);
if (state === 'active') qb.where((b) => b.where('mailbox_state', 'active').orWhereNull('mailbox_state'));
else qb.where('mailbox_state', state);
if (q) qb.where((b) => b.where('from_address', 'like', `%${q}%`).orWhere('subject', 'like', `%${q}%`));
return qb;
};
const countRow = await applyAccount(db('received_emails')).count({ c: '*' }).first();