Zammad sync performance + liitteiden näyttö tikettilistassa

- Rajoita artikkelien haku max 10 tikettiin per sync (loput on-demand)
- Curl timeout 15s + connect timeout 5s
- Frontend: IMAP ja Zammad haetaan rinnakkain (Promise.allSettled)
- Auto-refresh: Zammad sync ei blokkaa tikettien latausta
- Hakaneula-ikoni (📎) tikettilistassa kun viestissä on liitteitä
- has_attachments, source, zammad_group, ticket_number tikettilistaan

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-13 08:56:13 +02:00
parent dc0ed5c75c
commit a69fed75e4
3 changed files with 52 additions and 23 deletions

View File

@@ -1491,7 +1491,7 @@ function renderTickets() {
<td><span class="ticket-status ticket-status-${t.status}">${ticketStatusLabels[t.status] || t.status}</span></td>
<td>${t.customer_name ? esc(t.customer_name) : '<span style="color:#ccc;">-</span>'}</td>
<td><span class="ticket-type ticket-type-${t.type || 'muu'}">${typeLabel}</span></td>
<td>${prioBadge}${companyBadge}${t.ticket_number ? `<span style="color:#888;font-size:0.8rem;margin-right:0.3rem;">#${t.ticket_number}</span>` : ''}<strong>${esc(t.subject)}</strong></td>
<td>${prioBadge}${companyBadge}${t.ticket_number ? `<span style="color:#888;font-size:0.8rem;margin-right:0.3rem;">#${t.ticket_number}</span>` : ''}${t.has_attachments ? '<span title="Liitteitä" style="color:#888;margin-right:0.3rem;">📎</span>' : ''}<strong>${esc(t.subject)}</strong></td>
<td>${esc(t.mailbox_name || t.from_name || t.from_email)}</td>
<td style="text-align:center;">${lastType} ${t.message_count}</td>
<td class="nowrap" title="${esc((t.updated || '').substring(0, 16))}">${timeAgo(t.updated)}</td>
@@ -2145,22 +2145,33 @@ document.getElementById('btn-fetch-emails').addEventListener('click', async () =
status.textContent = 'Yhdistetään sähköpostipalvelimeen...';
try {
const result = await apiCall('ticket_fetch', 'POST');
let statusMsg = `Valmis! ${result.new_tickets} uutta tikettiä, ${result.threaded} ketjutettu viestiä.`;
// Hae IMAP ja Zammad rinnakkain — ei enää peräkkäin
status.textContent = 'Haetaan sähköpostit ja synkataan Zammad...';
const [imapResult, zammadResult] = await Promise.allSettled([
apiCall('ticket_fetch', 'POST'),
apiCall('zammad_sync', 'POST', { full: true }),
]);
// Hae myös Zammadista (full sync)
let zammadMsg = '';
try {
status.textContent = 'Synkataan Zammad...';
const zResult = await apiCall('zammad_sync', 'POST', { full: true });
if (zResult.created || zResult.updated || zResult.messages_added) {
zammadMsg = ` Zammad: ${zResult.created} uutta, ${zResult.updated} päivitettyä, ${zResult.messages_added} viestiä.`;
}
} catch (ze) { /* Zammad ei käytössä tai virhe — ohitetaan */ }
let parts = [];
if (imapResult.status === 'fulfilled') {
const r = imapResult.value;
parts.push(`📧 ${r.new_tickets} uutta, ${r.threaded} ketjutettu`);
} else if (imapResult.reason) {
parts.push(`📧 Virhe: ${imapResult.reason.message || 'tuntematon'}`);
}
if (zammadResult.status === 'fulfilled' && zammadResult.value.ok) {
const z = zammadResult.value;
const zParts = [];
if (z.created) zParts.push(`${z.created} uutta`);
if (z.updated) zParts.push(`${z.updated} päivitettyä`);
if (z.messages_added) zParts.push(`${z.messages_added} viestiä`);
if (z.articles_deferred) zParts.push(`${z.articles_deferred} tiketin viestit haetaan kun avaat`);
if (zParts.length) parts.push(`🔗 Zammad: ${zParts.join(', ')}`);
}
status.style.background = '#eafaf1';
status.style.color = '#27ae60';
status.textContent = statusMsg + zammadMsg;
status.textContent = parts.length ? parts.join(' | ') : 'Valmis — ei uusia viestejä.';
await loadTickets();
} catch (e) {
status.style.background = '#fef2f2';
@@ -2185,8 +2196,8 @@ function startTicketAutoRefresh() {
const supportActive = document.getElementById('tab-content-support').classList.contains('active');
const listVisible = document.getElementById('ticket-list-view').style.display !== 'none';
if (supportActive && listVisible) {
// Synkkaa Zammad taustalla ennen tikettien latausta
try { await apiCall('zammad_sync', 'POST'); } catch (e) { /* Zammad ei käytössä */ }
// Synkkaa Zammad taustalla JA lataa tiketit rinnakkain — ei blokkaa
apiCall('zammad_sync', 'POST').catch(() => {});
loadTickets();
}
}, seconds * 1000);