/** * ActivityLogView — Storico Attività * Displays the local SQLite activity log with filters, dual pagination, * and an expandable JSON detail panel. */ const ActivityLogView = { currentPage: 1, perPage: 50, filters: { esito: '', agente_id: '', da: '', a: '' }, async render() { this.currentPage = 1; const container = document.getElementById('view-container'); container.innerHTML = '

Caricamento storico...

'; await this._draw(); }, async _draw() { const container = document.getElementById('view-container'); try { const params = new URLSearchParams({ page: this.currentPage, per_page: this.perPage, }); if (this.filters.esito) params.set('esito', this.filters.esito); if (this.filters.agente_id) params.set('agente_id', this.filters.agente_id); if (this.filters.da) params.set('da', this.filters.da); if (this.filters.a) params.set('a', this.filters.a); const data = await App.api(`/api/attivita?${params}`); const { rows, total, page, per_page, total_pages } = data; container.innerHTML = this._buildHtml(rows, total, page, per_page, total_pages); this._bind(); } catch (err) { container.innerHTML = `

Errore caricamento: ${App.escapeHtml(err.message)}

`; } }, _buildHtml(rows, total, page, per_page, total_pages) { const filtersHtml = this._buildFilters(); const paginationHtml = this._buildPagination(total, page, per_page, total_pages); const tableHtml = rows.length === 0 ? `

Nessuna attività registrata.

` : `
${rows.map(r => this._buildRow(r)).join('')}
Data/Ora Agente Azione Ticket (TN) Esito ≡
`; return `
Storico Attività ${total} record
${filtersHtml} ${paginationHtml} ${tableHtml} ${rows.length > 0 ? paginationHtml.replace(/id="pagination-top"/g,'id="pagination-bottom"') : ''} `; }, _extractTicketRef(r) { if (!r.azione) return '—'; try { const data = typeof r.azione === 'string' ? JSON.parse(r.azione) : r.azione; if (!data) return '—'; const tn = data.tn || data.ticket_tn || data.target_tn; const id = data.ticket_id || data.id || data.target_id; if (tn && id) { return `#${App.escapeHtml(String(tn))}`; } else if (tn) { return `#${App.escapeHtml(String(tn))}`; } else if (id) { return `#${id}`; } if (Array.isArray(data.tns) && data.tns.length > 0) { return data.tns.map(t => `#${App.escapeHtml(String(t))}`).join(', '); } if (Array.isArray(data.source_tns) && data.source_tns.length > 0) { return data.source_tns.map(t => `#${App.escapeHtml(String(t))}`).join(', '); } if (Array.isArray(data.ticket_ids) && data.ticket_ids.length > 0) { return data.ticket_ids.map(tid => `#${tid}`).join(', '); } return '—'; } catch (_) { return '—'; } }, _buildRow(r) { const dt = r.creato_il ? new Date(r.creato_il).toLocaleString('it-IT') : '—'; const ticketRef = this._extractTicketRef(r); const esitoBadge = r.esito === 'successo' ? `✓ successo` : `✕ errore`; return ` ${dt} ${App.escapeHtml(r.agente_nome || '—')} ${App.escapeHtml(r.titolo_azione)} ${ticketRef} ${esitoBadge}
${App.escapeHtml(this._prettyJson(r.azione))}
`; }, _prettyJson(str) { try { return JSON.stringify(JSON.parse(str), null, 2); } catch (_) { return str || ''; } }, _buildFilters() { return `
`; }, _buildPagination(total, page, per_page, total_pages) { if (total_pages <= 1) return ''; const from = (page - 1) * per_page + 1; const to = Math.min(page * per_page, total); const pageBtn = (p, label, disabled, active) => { const isDisabled = disabled || p === page; return ``; }; const pages = []; pages.push(pageBtn(1, '«', page === 1, false)); pages.push(pageBtn(page - 1, '‹', page === 1, false)); const rangeStart = Math.max(1, page - 2); const rangeEnd = Math.min(total_pages, page + 2); for (let p = rangeStart; p <= rangeEnd; p++) { pages.push(pageBtn(p, p, false, p === page)); } pages.push(pageBtn(page + 1, '›', page === total_pages, false)); pages.push(pageBtn(total_pages, '»', page === total_pages, false)); return `
Record ${from}–${to} di ${total}
${pages.join('')}
`; }, _bind() { // Filter apply document.getElementById('btn-apply-filters')?.addEventListener('click', () => { this.filters.esito = document.getElementById('filter-esito')?.value || ''; this.filters.da = document.getElementById('filter-da')?.value || ''; this.filters.a = document.getElementById('filter-a')?.value || ''; this.currentPage = 1; this._draw(); }); // Filter reset document.getElementById('btn-reset-filters')?.addEventListener('click', () => { this.filters = { esito: '', agente_id: '', da: '', a: '' }; this.currentPage = 1; this._draw(); }); // Detail expand/collapse document.querySelectorAll('.act-detail-btn').forEach(btn => { btn.addEventListener('click', () => { const rowId = btn.dataset.id; const detailRow = document.getElementById(`detail-${rowId}`); if (!detailRow) return; const isOpen = detailRow.style.display !== 'none'; detailRow.style.display = isOpen ? 'none' : 'table-row'; btn.textContent = isOpen ? '≡' : '✕'; }); }); // Pagination buttons (top and bottom share same .page-btn class) document.querySelectorAll('.page-btn').forEach(btn => { btn.addEventListener('click', () => { const p = parseInt(btn.dataset.page, 10); if (!isNaN(p)) { this.currentPage = p; this._draw(); document.getElementById('view-container')?.scrollIntoView({ behavior: 'smooth', block: 'start' }); } }); }); }, };